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

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 $<

Related

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.

Makefile: "ld: can't link with a main executable file" in C

I am trying to compile two c files, calutil.c and calutil.h into one executable. Here is my makefile:
CC = gcc
CFLAGS = -Wall -std=c11 -DNDEBUG
all: caltool
caltool: calutil.o caltool.o
$(CC) $(CFLAGS) calutil.o caltool.o
caltool.o: caltool.c
$(CC) $(CFLAGS) caltool.c -o caltool.o
calutil.o: calutil.c
$(CC) $(CFLAGS) -c calutil.c -o calutil.o
clean:
rm -rf *.o *.out
calutil.c has no main, while caltool.c has a main. I get the error
ld: can't link with a main executable file when I make. What is the cause of this?
The main problem is that some your recipe for linkage is missing the output file, and that your compilation is missing -c.
In case you're using GNU make, the following Makefile would be sufficient to do what you want to do:
CFLAGS:=-Wall -std=c11
CPPFLAGS:=-DNDEBUG
.PHONY: all
all: caltool
caltool: caltool.o calutil.o
.PHONY: clean
clean::
$(RM) *.o
Explanation:
When you're not using target-specific variables, you should use := instead of = to assign variables so that they're expanded at assignment and not at evaluation.
When your Makefile grows and you split it, you might want to have multiple targets called clean which all would be executed. In that case use clean:: instead of clean:.
There's a predefined variable to call rm, it is $(RM) and it includes the -f flag to prevent the Makefile from failing in case one or more of the files to be removed do not exist in the first place.
The pattern for clean should be *.[adios] (that's really easy to remember, adios is Spanish for goodbye) so that it removes intermediate archives (.a when you build your own static libraries), dependency files (.d), preprocessor output (.i) and assembler files (.s) in case you use -save-temps to see what the compiler is doing.
GNU make has built-in rules to compile and link, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c?id=3.81
The built-in rule for compilation calls $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $< so you don't need to write your own rule.
The built-in rule for linkage calls $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $#
Targets which are not files themselves should be declared .PHONY to prevent confusion when a user creates a file with the same name, like all or clean.
I do not see how any of your commands would create a file matching the glob pattern *.out, so I removed that part of the clean rule.
Flags for the preprocessor should go into CPPFLAGS instead of CFLAGS. Preprocessor flags typically are all those -D and -I flags and would also be passed to other tools that use a C preprocessor in the same project, like splint or PC-Lint.
When the Makefile is run, it is looking how to make all, and it finds that for all it has to make caltool. For caltool it finds that it has to first make calutil.o and caltool.o. When it tries to make calutil.o and caltool.o, it finds that it can make them from calutil.c and caltool.c and will do so. Then it will link caltool.o and calutil.o into caltool.
From your naming I guessed that it's caltool.c that contains the main() function. It is helpful to place the object which contains main() first once you use static link libraries.
Edit: Here's some more magic for you. I assume that you have a header file calutil.h which is included by caltool.c to access extern symbols provided by calutil.c. You want to rebuild all objects that depend on these header files. In this case, add the following lines to your Makefile:
CPPFLAGS+=-MMD
-include caltool.d calutil.d
In order to not have the list of objects multiple times, you could add a variable objects like this:
objects:=caltool.o calutil.o
You would then build the application with this rule:
caltool: $(objects)
And include the dependency files like this:
-include $(objects:.o=.d)
In case you keep your working tree "clean", i.e. do not "pollute" it with "alien" code, i.e. you always want to include all .c files in your project, you can change the definition of objects as follows:
sources:=$(wildcard *.c)
objects:=$(sources:.c=.o)
In case you wonder why it is CPPFLAGS (uppercase) but objects (lowercase): it is common to use uppercase for all variables which configure the recipes of rules and control the built-in behavior of make, tools built on top of it, and classic environment variables, and lowercase variables for everything else.
I just removed the .o files from the directory, and edited my makefile to add -c to the caltool.o line.

How to make cc look into /usr/local/include for header files

I encountered this problem while installing some python modules in which had dependencies on their own C libraries. The problem is, cc is not looking into /usr/local/include at all for header files. I made it work for one of those (thinking it was a problem of the modules) by adding /usr/local/include as one of the external include directories.
Then, to test, I wrote a simple hello.c file and added #include "fftw3.h" / #include <fftw3.h> and it failed to compile if I didn't explicitly add -I/usr/local/include.
I added a line in my ~/.bash_profile to export the include the directory path to $PATH; didn't work either.
So, my question is, how do I make cc look for header files in /usr/local/include (or, for that matter, in any custom directory) always without passing -I flag?
FYI: I'm using macbook pro running OSX 10.11
If you are using GCC then you have three environment variables you can use:
CPATH
C_INCLUDE_PATH
CPLUS_INCLUDE_PATH
Take a look here.
EDIT: since you specified you are working with OS X (hence Clang), they should be supported too, take a look ad the end here. It's not uncommon to have Clang mimic GCC specs just to help in compatibility.
I think you should invest some time in understanding build systems. For example gnu make. Here, look at this:
CC = gcc
CFLAGS = -Wall
DEPS = primes.h
OBJ = go.o primes.o
%.o: %.c $(DEPS)
$(CC) $(CFLAGS) -c -o $# $<
go: $(OBJ)
gcc $(CFLAGS) -o $# $^
This gives you:
The freedom to add any compiler you want. In your case that would be cc, in this example it is gcc.
use cflags to control to adjust the compiler - in the example -Wall will turn on the warnings
make your build work reproducible
prepare recipe with complex rules for compilation as your application grow
More information is available here.

make command to replace constants in code

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;

Compiling with flags in a Makefile

To clarify things, let's suppose I'm compiling a program (prg) with 3 files, main.c, person.h and person.c.
If I use a concise way of writing the makefile, like this (more specifically the two last lines):
prg : main.o person.o
gcc -Wall -o prg -c $^
main.o : person.h
person.o : person.h
Will the -Wall be applied to main.o and person.o automatically? Or that doesn't even matter?
I know that, as the file says, if person.o needs to be re-compiled, prg will need a re-build too. But, I don't know if specifying -Wall only in the main goal is enough to enable it the other targets so warnings are emitted as the others are compiled.
Maybe I'm missing something really important, or I'm saying something that makes no sense; but take it easy, I'm just a beginner :P
Since you apply the -Wall to the link phase (when collecting the object files into an executable), but the option applies to the compilation phase (converting the source files into object files), it provides no benefit where it is written.
You should modify the compilation by setting macros.
Normally, the rule for compiling an C source file to an object file looks something like:
${CC} ${CFLAGS} -c $*.c
There could be other bits in there, and the notation might use something other than $*.c to identify the source file - there are similar (roughly equivalent) methods for specifying that, but it is tangential to the point I'm making. The $(CC) notation is equivalent to ${CC} too.
So, to change the compiler, you specify 'CC=new_c_compiler' and to change to compilation options, you (cautiously) specify 'CFLAGS=-Wall'.
This can be done in the makefile, or on the command line. The command line overrides the makefile.
Hence:
CFLAGS = -Wall
prg : main.o person.o
${CC} ${CFLAGS} -o prg -c $^
main.o : person.h
person.o : person.h
Why cautiously? Because in more complex situations, there may be a complex definition of CFLAGS which build it up from a number of sources, and blithely setting CFLAGS = -Wall may lose your include paths, macro definitions, and all sorts. In your case, it looks like you can simply set it as shown.
If you use GNU Make, you can simply add -Wall to CFLAGS:
CFLAGS += -Wall
This does not necessarily work with all varieties of make.
Your link line may eventually need to collect some library-related options too.
No, the flags will not magically be applied to other targets.
Add a line like this to the top of your Makefile, above the rules:
CFLAGS=-Wall
Then try without the explicit line for prg.

Resources