make command to replace constants in code - c

Sorry if this is a primitive question but I am really new in linux. Is there a way to replace constants in source code while building the application using make command?
I know the next possible method is to change the header files used in the source code, but I ask this because I have to program multiple microcontrollers and each one should have a unique integer as its number (this number is assigned as a constant in the code).
Any tips will be appreciated!

You could use a C language macro passed on the command line to the compiler. The usual Makefile snippet would look something like
CFLAGS = -DVERSION_INT=42 -DVERSION_STRING=\"Frobozz Magic Frobnicator (TM)\"
main: main.c
$(CC) $(CFLAGS) -o $# main.c
In main.c you might have
static int version = VERSION_INT;
static char vers[] = VERSION_STRING;

It is often done by defining preprocessor macros when invoking the compiler, e.g.:
# Makefile
NUMBER := 42
%.o : %.c
gcc -c -o $# ${CPPFLAGS} ${CFLAGS} -DNUMBER=${NUMBER} $<
In a source file:
// some.c
int number = NUMBER;

Related

Environment/Macros to command line for C make file [duplicate]

In the process of learning TinyOS I have discovered that I am totally clueless about makefiles.
There are many optional compile time features that can be used by way of declaring preprocessor variables.
To use them you have to do things like:
CFLAGS="-DPACKET_LINK" this enables a certain feature.
and
CFLAGS="-DPACKET_LINK" "-DLOW_POWER" enables two features.
Can someone dissect these lines for me and tell me whats going on? Not in terms of TinyOS, but in terms of makefiles!
CFLAGS is a variable that is most commonly used to add arguments to the compiler. In this case, it define macros.
So the -DPACKET_LINK is the equivalent of putting #define PACKET_LINK 1 at the top of all .c and .h files in your project. Most likely, you have code inside your project that looks if these macros are defined and does something depending on that:
#ifdef PACKET_LINK
// This code will be ignored if PACKET_LINK is not defined
do_packet_link_stuff();
#endif
#ifdef LOW_POWER
// This code will be ignored if LOW_POWER is not defined
handle_powersaving_functions();
#endif
If you look further down in your makefile, you should see that $(CFLAGS) is probably used like:
$(CC) $(CFLAGS) ...some-more-arguments...
Somewhere in the makefile the CFLAG will be used in compilation line like this:
$(CC) $(CFLAGS) $(C_INCLUDES) $<
and eventually in the execution will be translated to :
gcc -DPACKET_LINK -DLOW_POWER -c filename.c -o filename.o
This define will be passed to the source code as it was define in the header file
The -D option set pre-processor variables, so in your case, all code that is in the specified "#ifdef / #endif" blocks will be compiled.
I.e.
#ifdef PACKET_LINK
/* whatever code here */
#endif
The CFLAGS is a variable used in the makefile which will be expanded to it's contents when the compiler is invoked.
E.g.
gcc $(CFLAGS) source.c
-D stands for define (in gcc) at least, which lets you #define on the command line instead of a file somewhere. A common thing to see would be -DDEBUG or -DNDEBUG which respectively activate or disable debugging code.
Just for completeness in this - if you're using Microsoft's nmake utility, you might not actually see the $(CFLAGS) macro used in the makefile because nmake has some defaults for things like compiling C/C++ files. Among others, the following are pre-defined in nmake (I'm not sure if GNU Make does anything like this), so you might not see it in a working makefile on Windows:
.c.exe:
commands: $(CC) $(CFLAGS) $<
.c.obj:
commands: $(CC) $(CFLAGS) /c $<
.cpp.exe:
commands: $(CXX) $(CXXFLAGS) $<
.cpp.obj:
commands: $(CXX) $(CXXFLAGS) /c $<

Makefiles in C language

Hello I'm having a hard time understanding makefiles. I play with them to understand them better but here's the issue:
all: main
main: main.o funcIO.o funcMan.o
$(CC) -o $# $^
----------------------------------
funcIO.o: funcIO.c
$(CC) -c -o funcIO.o funcIO.c
funcMan.o: funcMan.o
$(CC) -c -o funcMan.o funcMan.c
This works regardless if everything below the punctured line is there or not. I'm told that this is the right way to write makefiles but why does it work without the targets funcIO.o and funcMan.o and if it works without them, why do we write them? Can you explain it like I'm 5 years old?
Thanks for your time!
Assuming you're using GNU Make (it might be the same for other Makes), this works due to built-in rules. Make already knows how to compile a C source file, and unless you tell it otherwise, it applies this recipe to it:
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$# is the target of the rule (the filename of the .o file) and $< is the first prerequisite (the filename of the .c file). The other variables have sensible defaults (mostly empty).
The right way to use Makefiles is to keep them as small as possible. Makefiles are about determining dependencies and only incidentally can be used to build programs. Here's how I would rewrite your Makefile:
all: main
main: main.o funcIO.o funcMan.o
And I only put the all target there because you had it to begin with. Make has a list of builtin rules that know how to build things given certain files as inputs. If you ask it for a .o file, it will look for a file of the same name, but with the extension of .c, .cpp, .f77, etc., and run the rule that builds what you asked for using that prerequisite file. You don't even need to specify how to build those, they come for free! It's the more complex relationships (such as a final binary) that need to be spelled out, as shown in my above example. There's a similar rule for building a binary out of .o files (assuming one of them has the same name as the binary, which yours does), so you don't need to specify any tasks, just the dependencies. You can control how they are run by adjusting special flags:
CFLAGS += -Wall -Wextra -Wpedantic
main: main.o funcIO.c funcMan.o
main: LDLIBS += -lm
This version builds every C-compiled file with those CFLAGS, and builds main while linking in the -lm math library.
If you are building normal C programs, I strongly recommend this approach. Specify the prerequisites of the final binary, and control builds through these Make variables.

Creating a generic makefile

I'm trying to create a makefile which would have as little command repetition as possible. Basic idea is to have variable name assigned at the target, like so:
CC = gcc
CFLAGS = -std=c99 -pedantic-errors -Wall
some_target:
P = some_target
some_other_target:
P = some_other_target
...
#common compilation command
$(CC) $(CFLAGS) $(P).c -o $(P).o
So there's only one compilation command which receives variable P which is unique for each target. Obviously example above doesn't work, what do i need to change to make it correct?
This is already built in. The variable $< expands to the first dependency and $^ expands to all dependencies. There is also $? which expands to only those dependencies which are newer than the target. See the documentaion for a full list.
Make already knows how to compile a .c file into an .o file, but if you want to see how it's done, the pattern looks a bit different from yours.
some_command.o: some_command.c
other.o: other.c
%.o: %.c
$(CC) $(CCFLAGS) $< -o $#

Linking error: Undefined reference to functions that're defined in a separate file?

I'm probably forgetting something obvious that'll solve this. While there's other questions on SO with the same issue, none of the solutions have been applicable to my situation.
I have a main file, sim.c, a header file net.h, a header file friends.h, and a file with the functions, net.c. I have a makefile, which I created with gmakemake > Makefile, and its contents are very basic.
Header.mak (makefile template):
CFLAGS = -Wall -Wextra -pedantic -std=c99 -ggdb
LFLAGS = -ggdb
LDFLAGS =
Makefile relevant contents:
CPP_FILES =
C_FILES = net.c sim.c
PS_FILES =
S_FILES =
H_FILES = net.h friends.h
SOURCEFILES = $(H_FILES) $(CPP_FILES) $(C_FILES) $(S_FILES)
.PRECIOUS: $(SOURCEFILES)
OBJFILES =
#
# Main targets
#
all: net sim
net: net.o $(OBJFILES)
$(CC) $(CFLAGS) -o net net.o $(OBJFILES) $(CLIBFLAGS)
sim: sim.o $(OBJFILES)
$(CC) $(CFLAGS) -o sim sim.o $(OBJFILES) $(CLIBFLAGS)
#
# Dependencies
#
net.o: net.h
sim.o: net.h
My sim.c file contains:
#include "net.h"
#include "friends.h"
My header file contains the functions in net.c and defines them all as stubs. I copied and pasted them to create the function headers, so there shouldn't be any typos.
My net.c file contains:
#include "net.h"
Yet any time a function in sim.c tries to call a function in net.c, it errors on that line with:
"undefined reference to `function_name`".
How can I make sim.c able to access the functions in net.c?
The message undefined reference to 'function_name' implies that of all the object files you're giving to the linker, none of them has a definition for function_name. That means that either
You're not linking with net.o
net.c (as compiled) does not contain a definition for function_name -- by 'as compiled' I mean with all of the various preprocessor options you use on it.
Since you show neither your link command line nor the contents of net.c, we can't tell which is the problem.
edit
with your edit, we can see clearly that you have the first problem -- when you try to link sim, you do not include net.o on the link command line. Most commonly, you would link sim with a makefile entry like:
sim: sim.o net.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LDLIBS)
or more simply just:
sim: sim.o net.o
relying on the default make actions for linking object files
For the two functions "see" each other make sure that:
Both c/cpp files are included in the makefile
Both definition(c/cpp) and declaration (h) files contains the same definition of the function: name/params/return value
The function being called must not be static.
Make sure you don't declare (or include) the same type with different structure in the source files.
That should do, unless you are using a very old complier with even more evil things that can go wrong ;)

Makefile for multiple executables with common files

I need help in writing a makefile that creates two separate executables that depend on a common file. So, I have three source files: Master.c Common.c Worker.c, and three corresponding header files. Now, Master.c includes Master.h and Common.h. Similarly, Worker.c includes Worker.h and Common.h. I would like to create two executables, namely Master and Worker, using the same makefile. I have the following makefile, but it's not functioning properly because for each global variable declared in Common.h, I get the error "Multiple declarations" when I type make. Note that I do use #indef, #define, and #endif in all the header files.
CC = gcc
CFLAGS= -g -I -pthread -lpthread -std=c99
DEPS = Common.h
OBJ1 = Master.o Common.o
OBJ2 = Worker.o Common.o
%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
all: Master Worker
Master: $(OBJ1)
gcc -o $# $^ $(CFLAGS)
Worker: $(OBJ2)
gcc -o $# $^ $(CFLAGS)
clean:
rm -f *.o
Can you please help
Don't put the definitions of global variables into headers; instead, put them in one of the source files and only declare the variables in the header:
Common.h:
extern int foo; /* declaration only */
Common.c:
#include "Common.h"
int foo; /* definition */
Otherwise including the header in more than one translation unit violates the one-definition rule.
is the makefile above flawless?
No. I can see several issues, if you fix them then it would be "state-of-the-art":
(a bug) all targets should at least depend on $(MAKEFILE)
MAKEFILE := $(lastword $(MAKEFILE_LIST))
you will then also need to filter the $^ in the recipe: $(filter %.o, $^), which is a good practice anyway
use := instead of =, it is more efficient and makes the logic in your code easier to understand in general, should always be used by default, unless = is necessary
you are defining CC to be gcc then not using it but using gcc instead
consider generating dependencies automatically (grep the manual), in this small case not needed perhaps, but for a larger case you will need it - there is good support in gcc for that nowadays
use a "canned recipe" (grep the manual) for the repeating recipe
.PHONY: all clean
clean does not remove everything

Resources