Import variables from C preprocessor into Makefile - makefile

I want to create one Makefile for Windows and Linux builds. The problem is I have to link with different dynamic libraries for each platform. The C preprocessor may have few nice variables, for example _WIN32. How to extract this information?
The solution have to work with a cross compiler. I cannot create and then run a small program. I have only one, different variable, the CC, the environment may be the same.
The other way around is easy, the -D switch.
Similar but different questions:
Makefile that distincts between Windows and Unix-like systems
I use the same make program. Only the CC variable is different.

I don't know if you can get directly those variables but you can try this solution:
CPP=i686-w64-mingw32-cpp
CPPFLAGS= -P
WIN32=$(shell echo _WIN32 | $(CPP) $(CPPFLAGS))
iswin32:
#echo $(WIN32)
This example will output 1:
$ make iswin32
1
If you are dealing with multiple declarations consider also creating a file with all the declarations, preprocess it and include it in a makefile.
$ cat declaration
WIN32 = _WIN32

Based on answer from TTK
Create file with variables, something like this:
#ifdef _WIN32
-lgdi32 -lopengl32
#else
-lpthread -lX11 -lXxf86vm -lXcursor -lXrandr -lXinerama -lXi -lGL
#endif
And something like this to the Makefile:
A_FLAGS = $(strip $(shell $(CPP) -P $(CPPFLAGS) ./a_flags.cpp))
# or
A_FLAGS = $(strip $(shell $(CPP) -P -xc $(CPPFLAGS) ./a_flags))
$(CPP) – the C preprocessor executable, should be defined by the Make program
-P – the flag to inhibit generation of linemarkers
-xc – the flag to force preprocessor to treat file as C source
$(CPPFLAGS) – optional flags for the preprocessor defined by programmer

Related

why does g++ add includes differently within makefile?

I am new to make files and having an issue where the g++ command works when run on the command line but not within a make file. The following line works:
g++ -I/home/user/ml/dynet/dynet -I/home/user/ml/dynet main.cpp
but the following make file can't find the required header file
ai: main.o
g++ -I/home/user/ml/dynet/dynet -I/home/user/ml/dynet main.cpp
the main.cpp is simple
#include <iostream>
#include "dynet.h"
int main() {
std::cout << "Hello World!";
return 0;
}
when I run the make I get the error that it can't fine the
user#LAPTOP-AUOAPRL1:~/ml/ai$ make
g++ -c -o main.o main.cpp
main.cpp:3:10: fatal error: dynet.h: No such file or directory
#include "dynet.h"
Why would the same line run differently? where is it looking when run within make? Thank you
GNU Make in it's infinite wisdom has chosen to use it's built-in rules. You can run without them by make --no-builtin-rules. It's not nice to have that as a prerequisite for building your files, but it might be useful when debugging "strange behavior" as it proves whether it's the built-in rules interfering with your mental model or not.
As for the wisdom itself, you only say how to build ai from main.o - not how to build main.o. That is what you're seeing - the built-in rule for building main.o.
What I think you want to do instead is have the rule like this:
ai: main.cpp
g++ ...
A tip; you should prefer using the built-in rules and variables, as it makes the makefile a little simpler to manage:
# using built-in variables
CC := g++
CPPFLAGS := -I/home/user/ml/dynet/dynet -I/home/user/ml/dynet
# inspired by built-in rules
ai: main.o
$(CC) $(LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $#
See https://www.gnu.org/software/make/manual/html_node/Catalogue-of-Rules.html

Difference between preprocessor macros D__KERNEL__ and __KERNEL__

I am an absolute beginner in programming in linux kernel programming, so sorry if the question is to elementary.
Here https://www.oreilly.com/library/view/linux-device-drivers/0596000081/ch02s02.html I found following example:
# Change it here or specify it on the "make" command line
KERNELDIR = /usr/src/linux
include $(KERNELDIR)/.config
CFLAGS = -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include \ -O -Wall
ifdef CONFIG_SMP
CFLAGS += -D__SMP__ -DSMP
endif
all: skull.o
skull.o: skull_init.o skull_clean.o
$(LD) -r $^ -o $#
clean:
rm -f *.o *~ core
And my question is simply what is the difference between preprocessor macro __KERNEL__ and the used -D__KERNEL__? Especially what is the meaning of "-D" here? (by the way the same story with MODULE and -DMODULE).
-D is an option to the compiler (or preprocessor), telling it to define a macro. So putting -D__KERNEL__ on the compiler command line is exactly the same as putting #define __KERNEL__ at the top of the file. Likewise, -DFOO would define a macro named FOO.
No macro named D__KERNEL__ is being defined anywhere here.

make file preprocessor directive

I am not very experienced with make files and am trying to define a preprocessor variable in my make file,in Eclipse (linux).
It turns up a non trivial task,since as it seems am missing something...
Bellow you can find my make file's structure:
var_first=g++
all:
g++ main_cell.cpp -o hello
in this way am building my code,that i want to do is to define a variable in my make files that would then be asserted with an #ifdef,#endif in my code.
I have gone through numerous combinations but am missing some steps as it seems...
Could you please give some pointers?
To add a definition while compiling, use the -D g++ option. Like this:
g++ -DMyDefine=123 main_cell.cpp -o hello
Now in main_cell.cpp you can do:
#if MyDefine == 123
doStuff();
#endif
To use makefile variables for this, do something like:
all: g++ main_cell.cpp -o hello -Dvar_first=$(var_first)
That is equivalent of #define var_first g++ in the .cpp file
If you want to pass the preprocessor variable directly to the compiler, you use a -D flag.
E.g. you want to define the variable PRE_MY_VAR to 1, you can write:
g++ -o myexecutable *.cpp -DPRE_MY_VAR=1
So in your makefile this would be:
all:
g++ main_cell.cpp -o hello -Dvar_first="g++"

Do I need to pass CFLAGS explicitly to gcc?

I read a lot of tutorials about CFLAGS and also looked in the official docs. Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler:
CFLAGS=-O2
gcc $(CFLAGS) -c foo.c -o foo.o
So, what does the term "implicit" mean in this context? If I declare CFLAGS=-O2 in my makefile and later just say gcc -c foo.c -o foo.o, will -O2 be active or not (so, is it really implicit)? If so, why do all tutorials (including official docs) still pass it explicitly in their examples?
Everywhere they say CFLAGS is implicit but still pass it explicitly in their example makefile to the compiler.
gcc does not use CFLAGS environment variable. See Environment Variables Affecting GCC.
CFLAGS is a conventional name for a Makefile variable with C-compiler flags and it is used by implicit make rules. See Variables Used by Implicit Rules for more details.
If you use your own make rules instead of the built-in ones, you do not need to use CFLAGS at all. Although it is a useful convention to do so because people are familiar with the conventional make variable names.
I believe CFLAGS is implicitly passed to the compiler command line by the makefile via the default compilation rule... Yet the CFLAGS can be overridden with custom flags so that each compilation command will take it and use.
You can test it easily:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
$ make -f cflags.mak
cc -wrong -c -o foo.o foo.c
cc: unrecognized option '-wrong'
So you can see it used the value of CFLAGS even though it was not explicitly specified in a rule; thus it is implicit.
But if you do specify your own rule for compiling .c files, you have to include it if you want it used:
$ cat cflags.mak
CFLAGS = -wrong
foo.o: foo.c
gcc -c $<
$ make -f cflags.mak
gcc -c foo.c
Here I provided my own rule for .c files which did not include CFLAGS, so CFLAGS was not used.
So the bottom line is if you rely on the built-in make rule for compiling .c files, CFLAGS will be included implicitly. But if you override that rule, you have to include it explicitly if you still want it to be used.
It means that there are implicit make rules, that use the CFLAGS, you can use.
So you can write a one line makefile with:
CFLAGS=-O2
if you later do:
make filename
(omitting extension) it will use an implicit rule that references the CFLAGS to convert you source file .c in an executable, so you don't need to write an explicit build statement for simple builds.
E.g. if you prepared a source name file.c it will build it with an implicit rule like:
$GCC $CFLAGS file.c -o file $LDFLAGS
see: GNU make documentation

makefiles CFLAGS

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

Resources