(g)make subroutine or procedure? - makefile

I have a (g)make script that covers a lot of microcontroller targets. A sequence of if blocks test for the various targets and set (or append) a lot of variables.
ifeq ($(CHIP),lpc1114fn28)
CORE_FLAGS := -mcpu=cortex-m0 -mthumb
CORE_FLAGS += -nostartfiles -fno-exceptions
CORE_CPP_FLAGS += -fno-threadsafe-statics -fno-use-cxa-get-exception-ptr
XTAL := 12000000
. . .
endif
There is a lot of duplication, which I'd like to factor out. I tried
define Cortex-M0 =
CORE_FLAGS := -mcpu=cortex-m0 -mthumb
CORE_FLAGS += -nostartfiles -fno-exceptions
endef
ifeq ($(CHIP),lpc1114fn28)
$(eval $(Cortex-M0))
CORE_CPP_FLAGS += -fno-threadsafe-statics -fno-use-cxa-get-exception-ptr
XTAL := 12000000
. . .
endif
But this does not seem to work. Is there a way to execute a subroutine-like construct that can contain multiple lines? I know I could use include files but I'd like to keep everything in one file.

If this isn't working then most likely your version of GNU make is older than 3.82. The syntax define VARIABLE = was introduced in that version; older versions don't allow you to use the assignment operator (=, :=, etc.) If make sees it there it will assign a variable named, literally, VARIABLE = (or in your case, Cortex-M0 =).
Remove the = at the end of the define line and it will work with older versions of GNU make.
Remember that the online version of the manual describes the latest version of GNU make; if you're not using that version, you should be careful that the version you're using supports the features you want. It's always safest to read the version of the manual that is provided to you along with the package of GNU make that you are using: whether it's your package manager or you downloaded it from somewhere yourself.

may be this:
ifeq ($(CHIP),lpc1114fn28)
$(eval $(call Cortex-M0))

Related

findstring in MAKEFLAGS don't working with ifeq

I'm trying to use find_j=$(findstring j,$(filter-out --%,$(MAKEFLAGS))) to find if there is -j option, so when I echo $(find_j) the value is j
but when I compare it ifeq (j, $(find_j)) this returnes false
I cant understand where is the problem
my version of make is make-3.99.90
find_j=$(findstring -j,$(filter-out --%,$(MAKEFLAGS)))
ifneq ( , $(find_j))
PARALLEL_ENABLED=true
endif
.PHONY: PRINT
PRINT:
$(info $(PARALLEL_ENABLED))
$(info $(MAKEFLAGS))
$(info $(find_j))
---empty line---
--warn-undefined-variables -ws --jobserver-fds=5,6 -j
-j
One thing to note is that the release of GNU make you're using is a beta release of GNU make 4.0, which itself was released in 2013... so you're using a beta of a release that itself is 8.5 years old.
However, that's not related to this problem.
The issue is that the MAKEFLAGS variable's final value is not set until after all makefiles are parsed. If you try to examine it before all makefiles are parsed, it will contain only a subset of the total set of options.
When you expand that variable as part of an ifeq or ifneq statement, that happens as the makefile is being parsed and so (as per the above) only the simple options (ones that don't take an argument: -j accepts an argument so is not "simple") are available.
When you expand the variable as part of a recipe, that happens after all makefiles are parsed: at that time the final value of MAKEFLAGS is set. So your $(info ...) functions inside the recipe do the right thing.
This is easy to see:
$(info no recipe MAKEFLAGS is '$(MAKEFLAGS)')
all: ; $(info in recipe MAKEFLAGS is '$(MAKEFLAGS)')
If you run with -j10 you'll get:
no recipe MAKEFLAGS is ''
in recipe MAKEFLAGS is '-j10 --jobserver-auth=3,4'
(your "in recipe" flags might look different because you're using such an old version of GNU make).
In the next release of GNU make, the value of MAKEFLAGS is kept up-to-date constantly so you can check it at any time and it will be accurate. But that release is not available yet.
This seems to be imprecisely documented. While MAKEFLAGS has the flags like e.g. -s and -k as ks in it, the -j flag gets processed in another way: it is not stripped of the leading dash - AND it is not visible in the first pass of processing the makefile. Only when rules are executed, MAKEFLAGS receives a value, albeit a processed form of the one you gave. -j3 elicits a -j3 --jobserver-auth=3,4 response from the command line transcriber of make, while -j stays -j. So what does this mean for us? Obviously the feature to detect the requested parallelism at runtime is not stable or there are some good reasons not to access them (which is the case most of the time when you encounter exceptional behaviour in GNU tools), so maybe you can give us more information on what you are trying to achieve - maybe there is a way to circumvent accessing the command line.

Make: Override a flag

I was a little confused with the responses to Quick way to override -Werror flag?
So I ask my specific question here.
I have multiple Makefiles working together and CFLAGS has been set along the way to (-Werror -Wall .. and many others)
But in one of the Makefiles, I wish that the errors not be treated as warnings and so I would like to remove -Werror flag.
What would be the best way to achieve this, so that only for this Makefile, -Werror flag is removed and for the others normal execution takes place?
Thanks,
Sunny
The right way to do this is with the filter-out function.
Put
CFLAGS := $(filter-out -Werror,$(CFLAGS))
in the Makefile where you want to override this, and the -Werror part of CFLAGS will be removed in that Makefile.
You can even use this to override flags for a single target by using target-specific variable values:
CFLAGS = -Werror
all: foo bar
foo:
echo cc $(CFLAGS) -o $#
bar: CFLAGS := $(filter-out -Werror,$(CFLAGS))
bar:
echo cc $(CFLAGS) -o $#
foo will be built with the default CFLAGS containing -Werror, but bar will be built without.
This is a general-purpose solution that works for all arguments to all programs, rather than requiring each program to supply a --no-foo for every --foo option.
Because it can’t be done from Make command-line, it doesn’t directly answer the question you linked to. But overriding Make variables from the command-line to force stuff to build is a pretty good way to make your unbuildable code even less maintainable!
Simpler way
It looks like you can invoke
gcc -c ... -Werror ... -Wno-error ...
without having GCC complain (GCC 4.7.1). So, you can add -Wno-error to the CFLAGS set up elsewhere in the one makefile where you need it. If you're using GNU make, in the one makefile, you can add:
CFLAGS += -Wno-error
possibly for just the single target that needs it.
Harder way
Otherwise, you need a system for building CFLAGS from components. What I have in the makefile I use for testing answers to questions on SO is:
WFLAG1 = -Wall
WFLAG2 = -Wextra
WFLAG3 = -Wmissing-prototypes
WFLAG4 = -Wstrict-prototypes
WFLAG5 = -Wold-style-definition
WFLAG6 =
WFLAGS = ${WFLAG1} ${WFLAG2} ${WFLAG3} ${WFLAG4} ${WFLAG5} ${WFLAG6}
SFLAGS = -std=c99
GFLAGS = -g
OFLAGS = -O3
UFLAGS =
IFLAG1 = -I${HOME}/inc
IFLAGS = # ${IFLAG1}
CFLAGS = ${OFLAGS} ${GFLAGS} ${IFLAGS} ${SFLAGS} ${WFLAGS} ${UFLAGS}
The main point is that each flag is independently adjustable; I can control the warning flags by setting any of ${WFLAG1} to ${WFLAG6}, or by setting ${WFLAGS} wholesale on the command line, or (indeed) by setting ${CFLAGS}. But because each is individually adjustable, and can tune the warnings relatively easily (the main hassle being determining which WFLAGn needs clobbering).
The UFLAGS is 'user flags' and is only set on the command line; I can add more flags to my command line by setting it.
This way is 'harder' because it requires you to modify the central part of your makefile system where you set CFLAGS. It is also less likely to be understood by your colleagues at first sight.
You can see an example of variable overriding in Git Makefile with CFLAGS which now can be tweaked when invoking Make while using DEVELOPER=YesPlease, with Git 2.22 (Q2 2019)
DEVELOPER (in Git Makefile) is a variable to group more compiler warning.
See commit 6d5d4b4, commit 71a7894, commit 8fb2a23, commit 65260a4, commit 9559f8f, commit 4f14a8c (22 Feb 2019) by Ævar Arnfjörð Bjarmason (avar).
(Merged by Junio C Hamano -- gitster -- in commit 3cef676, 20 Mar 2019)
Makefile: allow for combining DEVELOPER=1 and CFLAGS="..."
Ever since the DEVELOPER=1 facility introduced there's been no way to have custom CFLAGS (e.g. CFLAGS="-O0 -g -ggdb3") while still benefiting from the set of warnings and assertions DEVELOPER=1 enables.
This is because the semantics of variables in the Makefile are such
that the user setting CFLAGS overrides anything we set, including what
we're doing in config.mak.dev.
So let's introduce a "DEVELOPER_CFLAGS" variable in config.mak.dev and
add it to ALL_CFLAGS. Before this the ALL_CFLAGS variable
would (basically, there's some nuance we won't go into) be set to:
$(CPPFLAGS) [$(CFLAGS) *or* $(CFLAGS) in config.mak.dev] $(BASIC_CFLAGS) $(EXTRA_CPPFLAGS)
But will now be:
$(DEVELOPER_CFLAGS) $(CPPFLAGS) $(CFLAGS) $(BASIC_CFLAGS) $(EXTRA_CPPFLAGS)
The reason for putting DEVELOPER_CFLAGS first is to allow for
selectively overriding something DEVELOPER=1 brings in.
On both GCC and Clang later settings override earlier ones.
E.g. "-Wextra -Wno-extra" will enable no "extra" warnings, but not if those two
arguments are reversed.
Examples of things that weren't possible before, but are now:
# Use -O0 instead of -O2 for less painful debuggng
DEVELOPER=1 CFLAGS="-O0 -g"
# DEVELOPER=1 plus -Wextra, but disable some of the warnings
DEVELOPER=1 DEVOPTS="no-error extra-all" CFLAGS="-O0 -g -Wno-unused-parameter"
The reason for the patches leading up to this one re-arranged the
various *FLAGS assignments and includes is just for readability.
The Makefile supports assignments out of order, e.g.:
$ cat Makefile
X = $(A) $(B) $(C)
A = A
B = B
include c.mak
all:
#echo $(X)
$ cat c.mak
C=C
$ make
A B C

CFLAGS vs CPPFLAGS

I understand that CFLAGS (or CXXFLAGS for C++) are for the compiler, whereas CPPFLAGS is used by the preprocessor.
But I still don't understand the difference.
I need to specify an include path for a header file that is included with #include -- because #include is a preprocessor directive, is the preprocessor (CPPFLAGS) the only thing I care about?
Under what circumstances do I need to give the compiler an extra include path?
In general, if the preprocessor finds and includes needed header files, why does it ever need to be told about extra include directories? What use is CFLAGS at all?
(In my case, I actually found that BOTH of these allow me to compile my program, which adds to the confusion... I can use CFLAGS OR CPPFLAGS to accomplish my goal (in autoconf context at least). What gives?)
The implicit make rule for compiling a C program is
%.o:%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $# $<
where the $() syntax expands the variables. As both CPPFLAGS and CFLAGS are used in the compiler call, which you use to define include paths is a matter of personal taste. For instance if foo.c is a file in the current directory
make foo.o CPPFLAGS="-I/usr/include"
make foo.o CFLAGS="-I/usr/include"
will both call your compiler in exactly the same way, namely
gcc -I/usr/include -c -o foo.o foo.c
The difference between the two comes into play when you have multiple languages which need the same include path, for instance if you have bar.cpp then try
make bar.o CPPFLAGS="-I/usr/include"
make bar.o CFLAGS="-I/usr/include"
then the compilations will be
g++ -I/usr/include -c -o bar.o bar.cpp
g++ -c -o bar.o bar.cpp
as the C++ implicit rule also uses the CPPFLAGS variable.
This difference gives you a good guide for which to use - if you want the flag to be used for all languages put it in CPPFLAGS, if it's for a specific language put it in CFLAGS, CXXFLAGS etc. Examples of the latter type include standard compliance or warning flags - you wouldn't want to pass -std=c99 to your C++ compiler!
You might then end up with something like this in your makefile
CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
The CPPFLAGS macro is the one to use to specify #include directories.
Both CPPFLAGS and CFLAGS work in your case because the make(1) rule combines both preprocessing and compiling in one command (so both macros are used in the command).
You don't need to specify . as an include-directory if you use the form #include "...". You also don't need to specify the standard compiler include directory. You do need to specify all other include-directories.
You are after implicit make rules.
To add to those who have mentioned the implicit rules, it's best to see what make has defined implicitly and for your env using:
make -p
For instance:
%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
which expands
COMPILE.c = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c
This will also print # environment data. Here, you will find GCC's include path among other useful info.
C_INCLUDE_PATH=/usr/include
In make, when it comes to search, the paths are many, the light is one... or something to that effect.
C_INCLUDE_PATH is system-wide, set it in your shell's *.rc.
$(CPPFLAGS) is for the preprocessor include path.
If you need to add a general search path for make, use:
VPATH = my_dir_to_search
... or even more specific
vpath %.c src
vpath %.h include
make uses VPATH as a general search path so use cautiously. If a file exists in more than one location listed in VPATH, make will take the first occurrence in the list.
I installed httpd on Ubuntu 18.04 using the CPPFLAGS variable for the -DLINUX flag. When run, CPPFLAGS scans the code from top to bottom, file by file, looking for directives before compiling, and will not be extended by other meaningful things like size optimization, flags that do not increase the size of the output file; under the type of processor; to reduce the size of the code and speed up the program; disable all variables except case. The only difference between CPPFLAGS and CFLAGS is that CFLAGS can be set to specify additional switches to be passed to the compiler. That is, the CFLAGS environment variable creates a directory in the installation path (eg CFLAGS=-i/opt/include) to add debugging information to the executable target's path: include general alarm messages; turning off alarm information; independent location generation; display compiler driver, preprocessor, compiler version number.
Standard way to set CPPFLAGS:
sudo ./configure --enable-unixd=DLINUX #for example
list of some known variables:
CPPFLAGS - is the variable name for flags to the C preprocessor.
CXXFLAGS - is the standard variable name for flags to the C++ compiler.
CFLAGS is - the standard name for a variable with compilation flags.
LDFLAGS - should be used for search flags/paths (-L) - i.e. -L/usr/lib (/usr/lib are library binaries).
LDLIBS - for linking libraries.
CPPFLAGS seems to be an invention of GNU Make, referenced in some of its built-in recipes.
If your program is built by some Free software distributions, you may find that some of them require packages to interpolate this variable, using CPPFLAGS for passing down options like -D_WHATEVER=1 for passing down a macro definition.
This separation is a poor idea and completely unnecessary in the GNU environment because:
There is a way to run gcc to do preprocessing only (while ignoring compiler options unrelated to preprocessing).
The stand-alone GNU cpp is tolerant to compiler options, such as -W warnings that do not pertain to preprocessing and even code generation options like -fstrict-aliasing and the linker-pass through like -Wl,--whatever.
So generally speaking, build systems that need to call the stand-alone preprocessor for whatever reason can just pass it $(CFLAGS).
As an application developer writing a Makefile, you cannot rely on the existence of CPPFLAGS. Users who are not insider experts in open source building won't know about CPPFLAGS, and will do things like make CFLAGS=-Dfoo=bar when building your program. If that doesn't work, they will be annoyed.
As a distro maintainer, you cannot rely on programs to pull in CPPFLAGS; even otherwise well-behaved ones that pull in CFLAGS, LDFLAGS and LDLIBS.
It's easy enough for the application developers to write GNU Make code to separate preprocessor flags out of $(CFLAGS):
cpp_only_flags := $(foreach arg, \
$(CFLAGS), \
$(or $(filter -D%,$(arg)), \
$(filter -U%,$(arg)), \
$(filter -I%,$(arg)), \
$(filter -iquote%,$(arg)), \
$(filter -W%,$(arg)), \
$(filter -M%,$(arg)))) \
$(CPPFLAGS) # also pull this in
all:
#echo cpp_only_flags == $(cpp_only_flags)
Demo:
$ make CFLAGS="-Wall -I/path/to/include -W -UMAC -DFOO=bar -o foo.o -lm"
cpp_only_flags == -Wall -I/path/to/include -W -UMAC -DFOO=bar
In the case of the GNU compiler and preprocessor, this is probably unnnecessary; but it illustrates a technique that could be used for non-GNU compilers and preprocessors, in a build system based on GNU Make.

Adding a directory for the headers in a Makefile

Hello I would like to ask you, If someone knows how can I add a directory for the header files in the Makefile to avoid the error *.h not found, I have tried this option but does not work:
INC_PATH := -I /directory/to/add
At least for GNU make, try the implicit variable CFLAGS, as in:
CFLAGS=-I/directory/to/add
Although the goal is ultimately to affect the value of CFLAGS (as suggested by #unwind), it is often not a good idea to simply set the value of CFLAGS as it is often built out of many pieces. You have to understand the structure of the makefile, and the set of macros used.
[Added:
Eduardo asked: Can you post macros to do the same?
Yes, but whether they are helpful depends on how your makefiles are structured. Here's a moderately complex example from one of my makefiles.
CC = gcc -g
XFLAGS = -Wall -Wshadow -Wstrict-prototypes -Wmissing-prototypes \
-DDEBUG -Wredundant-decls
#CC = cc -g
#XFLAGS =
UFLAGS = # Always overrideable on the command line
DEPEND.mk = sqlcmd-depend.mk
INSTALL.mk = sqlcmd-install.mk
ESQLC_VERSION = `esqlcver`
OFLAGS = # -DDEBUG_MALLOC -g
OFLAGS = -g -DDEBUG -O4
PFLAGS = -DHAVE_CONFIG_H
OFILES.o = # rfnmanip.o # malloc.o # strdup.o # memmove.o
VERSION = -DESQLC_VERSION=${ESQLC_VERSION}
#INC1 = <defined in sqlcmd-depend.mk>
#INC2 = <defined in sqlcmd-depend.mk>
INC3 = /usr/gnu/include
INC4 = ${INFORMIXDIR}/incl/esql
INC5 = . #${INFORMIXDIR}/incl
INCDIRS = -I${INC3} -I${INC1} -I${INC2} -I${INC4} -I${INC5}
LIBSQLCMD = libsqlcmd.a
STRIP = #-s
LIBC = #-lc_s
LIBMALLOC = #-lefence
LIBRDLN = -lreadline
LIBCURSES = -lcurses
LIBPOSIX4 = -lposix4
LIBG = #-lg
LIBDIR1 = ${HOME}/lib
LIBDIR2 = /usr/gnu/lib
LIBJL1 = ${LIBDIR1}/libjl.a
LIBJL2 = ${LIBDIR1}/libjlss-${ESQLC_VERSION}.a
LIBTOOLS = ${LIBJL2} ${LIBJL1}
LDFLAGS = ${LIBSQLCMD} ${LIBTOOLS} -L${LIBDIR2} ${LIBG} ${LIBMALLOC} \
${LIBPOSIX4} ${LIBC} ${STRIP}
CFLAGS = ${VERSION} ${INCDIRS} ${OFLAGS} ${XFLAGS} ${PFLAGS} ${UFLAGS}
This a makefile for a program of mine called sqlcmd (a name chosen a decade and more before Microsoft created a command of the same name). I assume that the make program has a rule for compiling C code to object like:
${CC} ${CFLAGS} -c $*.c
and that the rule for linking a program from a set of object files listed in the macro OBJECTS looks like:
${CC} ${CFLAGS} -o $# ${OBJECTS} ${LDFLAGS}
As you can see, there are separately settable macros for the ESQLC_VERSION (the version of Informix ESQL/C in use, derived by default by runing a script esqlcver), then the include directories via INC1 to INC5 and INCFLAGS (there can be quite a lot of these, depending on platform), and optimizer flags (OFLAGS), extra flags (CFLAGS), user-defined flags (UFLAGS - an idiom I use in most of my makefiles; it allows the user to set UFLAGS on the make command line and add an extra flag to the build), and a bunch of library-related macros. This is what it takes for my development makefile to be tunable with minimal fuss to my development platform, which can be Linux, Solaris or MacOS X. For consumers of the program, there is a configure script generated by autoconf, so they don't have to worry about getting those bits right. However, that has a strong genetic resemblance to this code, including the UFLAGS option.
Note that many systems for makefile building have a mechanism for setting CFLAGS faintly similar to this - and simply assigning to CFLAGS undoes the good work done by the system. But you have to understand your makefile to be able to modify it sanely.
]

Good way to do a "switch" in a Makefile

I'm experimenting with an updated build system at work; currently, I'm trying to find a good way to set compiler & flags depending on the target platform.
What I would like to do is something like
switch $(PLATFORM)_$(BUILD_TYPE)
case "Linux_x86_release"
CFLAGS = -O3
case "Linux_x86_debug"
CFLAGS = -O0 -g
case "ARM_release"
CC = armcc
AR = armlink
CFLAGS = -O2 -fx
...
which is not supported by GNU Make. Now, my first thought was to just do
-include $(PLATFORM)_$(BUILD_TYPE)
which is a pretty decent solution, however, it makes it hard to get an overview of what differs between files, not to mention that I'm looking forward to writing & maintaining a good 60-80 files, each containing a set of variable definitions.
Does anyone happen to know a better way to accomplish this? I.e. setting a set of flags and other options based on another variable?
How about:
CFLAGS_Linux_x86_release = -O3
CFLAGS_Linux_x86_debug = -O0 -g
CFLAGS = ${CFLAGS_${PLATFORM}_${BUILD}}
Configuring such parameters would be the task of a configure script.
That being said, you can look into the syntax for conditionals and conditional functions. For example, you could try the following:
ifeq ($(PLATFORM)_$(BUILD_TYPE),Linux_x86_release)
CFLAGS = -O3
endif
ifeq ($(PLATFORM)_$(BUILD_TYPE),Linux_x86_debug)
CFLAGS = -O0 -g
endif
The Makefile used by git is a good example of a Makefile which does non-trivial configuration tasks in the Makefile itself (such as switching on the host type). It's actually quite readable and reasonably simple to use.
Switching to a system which does it for you (automake/autoconf) may be simpler...

Resources