How to set multiple variables in target makefile - c++

I have one problem. I cannot set multiple variables depending on target. I need to set two variables for example if makefile has been run with option cpp (target), two variables should be set,but I get only one variable (CC) set. But another is left as default.
cpp:EXTENSION=cpp
cpp:CC=g++
cpp:COMPILE
Please help with this problem.

I cannot set multiple variables depending on target.
In GNU Make, this is typically achieved by analyzing the content of the $(MAKECMDGOALS) variable and then setting the variables depending on the specified goals.
For example, a Makefile:
ifeq ($(filter cpp,$(MAKECMDGOALS)),cpp)
MSG=make cpp was called!
endif
ifeq ($(filter notcpp,$(MAKECMDGOALS)),notcpp)
MSG=make notcpp was called!
endif
all:
#echo possible targets: cpp, notcpp; false
notcpp cpp:
#echo $(MSG)
Running the make cpp would print make cpp was called!.
Running the make notcpp would print make notcpp was called!.
(Explanation of the ifeq ($(filter cpp,$(MAKECMDGOALS)),cpp) construct. The $(filter) function looks for the word (first argument, cpp) in the list (second argument, $(MAKECMDGOALS)). If it finds the word, it returns it. Otherwise, it returns an empty string. The ifeq then compares the result of the $(filter) function to the sought word: if equal, then the block til endif is parsed/executed. Alternatively, one could write ifneq ($(filter cpp,$(MAKECMDGOALS)),) to test that the result of $(filter) is not an empty string. For more info, see $(filter) and ifeq in GNU Make documentation. Additionally, about general function syntax and how to call a custom function.)
Another possibility is using multiple Makefiles. In the main Makefile, depending on the target you pass the control to the target-specific Makefile, e.g.:
cpp notcpp:
$(MAKE) -f Makefile.$# all
Use of target-specific includes is also a popular option.

Related

makefile file name parameter

I remember doing this in my advanced C++ class, but it's been a couple years and I forgot.
I want to make a sort of simple re-usable makefile where I just type "make programName" and it compiles programName.cpp into programName.exe.
I've looked for this for a couple hours, but haven't found what I need. I know this will get marked as duplicate, but at least point me to what I need.
Make has a built-in variable called $(MAKECMDGOALS), which contains all targets specified as command line parameters.
You can use it to generate recipes, like so:
# Stop if 0 or 2+ targets were specified.
$(if $(filter-out 1,$(words $(MAKECMDGOALS))),$(error Expected one target))
name := $(MAKECMDGOALS)
$(name).exe: $(name).cpp
g++ $^ -o $#
Adding a way to customize compiler executable and flags is left as an exercise to the reader. As well as conditionally removing .exe from the target name when building on Linux.
Why do you want your output to be suffixed with .exe? That's a Windows convention that is not followed on POSIX systems like Linux.
If you don't want that you don't even need a makefile at all. You can type make programName with no makefile and if you have a file programName.c, it will be built into an executable programName via make's built-in rules.

GNU recursive make - how to capture make variables to execute nested makefile

I have a bunch of qmake-generated makefiles each of which call make inside them (recursive make) in a chained manner.
After my build is over, the qmake-generated makefiles are all on disk so you'd think I could just call make on one of them if I wanted to 'replay' one particular makefile. Wrong.
When I try make-ing one, it fails, probably because there's a bunch of (environment) variables that it normally inherits from the calling makefile during the normal build.
Except for the variables, each qmake-generated makefile is pretty self-contained.
QUESTION
How can I simulate the 'normal' environment for a given recursive make so that I can call it in isolation?
I'm thinking I'd have to do something with the --print-data-base output: parse it and then call make with the same vars and values it had during the normal build.
WHY
I'm doing this because I need to modify the compile commands for ONE makefile but it's all controlled by the top-level .conf and I'm getting in way too deep.
I assume the problem is that you need to find this information before you get a chance to make any changes to the generated makefiles. Therefore, this solution is focused on shell commands (I'm assuming you're on Linux, since you don't say).
After starting your build, the first time, use something like:
ps -ef | head -1
ps -ef | grep make
to find make processes involved in the build. The PID column lists the Process ID of the make process, while the PPID column lists that of its parent. Use this information to find the top-level make process. Then, run:
strings /proc/<pid>/environ | sort > /tmp/make_env
env | sort > /tmp/normal_env
diff /tmp/normal_env /tmp/make_env
This will show you how the make process' environment differs from that of your current shell.
Now, that might not solve your problem, because GNU Make allows variables to be specified as commandline parameters. So, you should also check how it's being run:
strings /proc/<pid>/cmdline
That will print each commandline argument of <pid>, on a separate line.
BTW, when variables are passed to GNU Make via commandline arguments, they're handled by overriding any instance of the same variable, that might be contained within the makefile.
Within a makefile, you can see its environment using:
$(info My environment is $(shell env))
You can see its commandline options using:
$(info MAKEFLAGS = $(MAKEFLAGS))
If you only want to see the overrides, use MAKEOVERRIDES:
$(info MAKEOVERRIDES = $(MAKEOVERRIDES))
Finally, the targets can be seen using:
$(info MAKECMDGOALS = $(MAKECMDGOALS))

GNU make - rule in makefile in $(MAKEFILES) is not read/acknowledged

I have a makefile, ImpTarget.mk, defined with following content, taken from this example:
%.h: %.dummy_force
#echo header= $# xyz
%.dummy_force: ;
I include this file in the MAKEFILES variable
This is my top-level makefile (modified with the MAKEFILES variable)
MAKEFILES = "C:\Users\User1\Desktop\A\ImpTarget.mk"
all:
$(MAKE) -C src -f makefile_gen all
$(MAKE) -C src DEBUG=TRUE -f makefile_gen all
My goal is to turn all files - .h, .cpp, etc - in the prerequisites list into targets also i.e., executing make --print-database should yield a statement that every header file is also a target.
However, it's not working.
When I look at the database printed out, for each makefile I see that MAKEFILES is equal to "C:\Users\User1\Desktop\A\ImpTarget.mk" which is good because it means that it should be reading in ImpTarget.mk
3.4 The Variable MAKEFILES
If the environment variable MAKEFILES is defined, make considers its
value as a list of names (separated by whitespace) of additional
makefiles to be read before the others.
But it is not turning each file into a target. I still get:
# Not a target:
C:/Users/User1/Desktop/A/HMI_FORGF/qt5binaries/include/QtCore/qglobalstatic.h:
# Implicit rule search has been done.
# Last modified 2016-05-12 10:10:13
# File has been updated.
# Successfully updated.
In fact, the rule I defined is not even showing up in the --print-data-base part of the output.
I put the xyz as a marker so I could easily locate it in the listing of the rules that are executed but it doesn't appear in that list.
Why not use include?
Well first of all, what's the difference? Show me a link.
Secondly, yes that's the preferred method but some of my makefiles auto-generate a makefile, then inside that one generate another makefile and execute it.
So I don't have control over my build system enough to do that.
If the environment variable MAKEFILES is defined
Meaning make will only consider MAKEFILES if it is defined externally to make, either in the shell environment itself or by running make MAKEFILES=foo.mk.
MAKEFILES vs include is explained in the next paragraph
The main use of MAKEFILES is in communication between recursive invocations of make
You need to export the MAKEFILE variable into the environment. From 6.10 Variables from the Environment
When make runs a recipe, variables defined in the makefile are placed into the environment of each shell. This allows you to pass values to sub-make invocations (see Recursive Use of make). By default, only variables that came from the environment or the command line are passed to recursive invocations. You can use the export directive to pass other variables. See Communicating Variables to a Sub-make, for full details.
Since MAKEFILES wasn't found in the original environment, it isn't automatically passed into the environment. Use:
export MAKEFILES = "C:\Users\User1\Desktop\A\ImpTarget.mk"

How do I define a dependency graph with unknown intermediate node names?

I'm using a tool chain where I do not know the names of all of the intermediate files.
E.g. I know that I start out with a foo.s, and go through several steps to get a foo.XXXX.sym and a foo.XXXX.hex, buried way down deep. And then running other tools on foo.XXXX.hex and foo.XXXX.sym, I eventually end up with something like final.results.
But, the trouble is that I don't know what the XXXX is. It is derived from some other parameters, but may be significantly transformed away from them.
Now, after running the tool/steps that generate foo.XXXX.{sym,hex}, I now typically scan the overall result directory looking for foo.*.{sym,hex}. I.e. I have code that can recognize the intermediate outputs, I just don't know exactly what the names will be.
I typically use make or scons - actually, I prefer scons, but my team highly prefers make. I'm open to other build tools.
What I want to do is be able to say (1) "make final.results", or "scons final.results", (2) and have it scan over the partial tree; (3) figure out that, while it does not know the full path, it definitely knows that it has to run the first step, (4) after that first step, look for and find the foo.XXX.* files; (5) and plug those into the dependency tree.
I.e. I want to finish building the dependency tree after the build has already started.
A friend got frustrated enough with scons' limitations in this area that he wrote his own build tool. Unfortunately it is proprietary.
I guess that I can create a first build graph, say in make with many .PHONY targets, and then after I get through the first step, generate a new makefile with the new names, and have the first make invoke the newly generated second makefile. Seems clumsy. Is there any more elegant way?
GNU make has an "auto-rexec" feature that you might be able to make use of. See How Makefiles Are Remade
After make finishes reading all the makefiles (both the ones found automatically and/or on the command line, as well as all included makefiles), it will try to rebuild all its makefiles (using the rules it knows about). If any of those makefiles are automatically rebuilt, then make will re-exec itself so it can re-read the newest versions of the makefiles/included files, and starts over (including re-trying to build all the makefiles).
It seems to me that you should be able to do something with this. You can write in your main makefile and "-include foo.sym.mk" for example, and then have a rule that builds "foo.sym.mk" by invoking the tool on foo.s, then running your "recognized the next step" code and generate a "foo.sym.mk" file which defines a rule for the intermediate output that got created. Something like (due to lack of specificity in your question I can't give true examples you understand):
SRCS = foo.s bar.s baz.s
-include $(patsubst %.s,%.sym.mk,$(SRCS))
%.sym.mk: %.s
<compile> '$<'
<recognize output and generate makefile> > '$#'
Now when make runs it will see that foo.sym.mk is out of date (if it is) using normal algorithms and it will rebuild foo.sym.mk, which as a "side effect" causes the foo.s file to be compiled.
And of course, the "foo.sym.mk" file can include ANOTHER file, which can recognize the next step, if necessary.
I'm not saying this will be trivial but it seems do-able based on your description.
Make constructs the graph before running any rule, so there won't be a perfect answer. Here are some reasonably clean solutions.
1) use PHONY intermediates and wildcards in the commands. (You can't use Make wildcards because make expands them before running rules.)
final.results: middle
# build $# using $(shell ls foo.*.sym) and $(shell ls foo.*.hex)
.PHONY: middle
middle: foo.s
# build foo.XXXX.sym and foo.XXXX.hex from $<
2) Use recursive Make (which is not as bad as people say, and sometimes very useful.)
SYM = $(wildcard foo.*.sym)
HEX = $(wildcard foo.*.hex)
# Note that this is is the one you should "Make".
# I've put it first so it'll be the default.
.PHONY: first-step
first-step: foo.s
# build foo.XXXX.sym and foo.XXXX.hex from $<
#$(MAKE) -s final.results
final.results:
# build $# using $(SYM) and $(HEX)
3) Similar to 2, but have a rule for the makefile which will cause Make to run a second time.
SYM = $(wildcard foo.*.sym)
HEX = $(wildcard foo.*.hex)
final.results:
# build $# using $(SYM) and $(HEX)
Makefile: foo.s
# build foo.XXXX.sym and foo.XXXX.hex from $<
#touch $#

how to make a walk in a directory and find all files with a particular extension

I need to write a pre-build makefile which is called separately from the main build file. This make file should make a walk in a directory where it is called. There is a list of directories in another make file called 'sources.mk' with a variable which describe the directory:
SUBDIRS := \
. \
directory1 \
directory2 \
Now, I need to run a loop through this list and in this loop I need to call an utility which will process all file with a 'h' extension. I wrote this:
include Default/sources.mk
find_files:
for prefix in $(SUBDIRS); do \
for file in *.h; do \
C:/QtSDK/Desktop/Qt/4.7.4/mingw/bin/moc.exe $$prefix/$$file; \
done \
done
Run command: make -f premake.mk
I don't describe the errors, there are a lot of them, I was trying different makefiles, but I am a newbie at it and these attempts failed. Please, review my code and/or suggest other methods.
Your problem is probably just this one simple thing: You're looking for file in *.h in the current directory, not in the subdirectory. Try this instead:
for prefix in $(SUBDIRS); do \
for file in $$prefix/*.h; do \
C:/QtSDK/Desktop/Qt/4.7.4/mingw/bin/moc.exe $$file; \
done \
done
With that said, a much better way of doing this is to use make to handle the processing of all of the files (and deciding whether or not all of them need to be reprocessed!), rather than using an explicit loop in the rule. You'd start with a list of header files, as Eldar Abusalimov's answer suggests:
moc_headers := $(wildcard $(SUBDIRS:%=%/*.h))
The inner piece of that manipulates the SUBDIRS list into a form directory1/*.h, directory2/*.h, and so on, and then the wildcard function expands all the *.h patterns.
Then, you generate the list of output files from them:
moc_mocfiles := $(patsubst %.h, %_moc.cpp, $(moc_headers))
This takes that expanded list of header files directory1/header1.h, directory1/header2.h, and so on, and substitutes the %.h pattern with %_moc.cpp. (Note that, because these names all have the directory name as part of the name, you can't easily use the more common moc_%.h name pattern, because you'd get moc_directory1/header1.cpp, not the desired directory1/moc_header1.cpp. There are ways to get around that, but it's easier to avoid the problem.) In any case, this gives you a list of output files: directory1/header1_moc.cpp, directory1/header2_moc.cpp, and so on.
Now that you have a list of output files, Make knows how to iterate over those pretty easily. You just declare that list as a prerequisite of some other target that you're making, for instance:
find_files: $(moc_mocfiles)
And, finally, you give make a generic rule for making a *_moc.cpp file from a *.h file:
%_moc.cpp: %.h
C:/QtSDK/Desktop/Qt/4.7.4/mingw/bin/moc.exe $< -o $#
There, the first line indicates "this is how you make a file that fits the %_moc.cpp pattern, if you have a file fitting the %.h pattern to make it from". In the second line, the $< becomes the input file (the %.h file), and the $# becomes the output file. Here, you're explicitly telling moc.exe with the -o option to spit out a file with the %_moc.cpp name rather than whatever it uses by default.
So, putting all this together, when you make the find_files target, make will realize that it needs to make all those %_moc.cpp files in the moc_mocfiles list, and for each one it will see that it has a possible rule that fits, it will see that the rule applies because the corresponding %.h file exists, and it will apply the rule.
This also has the advantage that, if the %_moc.cpp file already exists and is newer than the %.h file, indicating that it's already up-to-date, it won't bother regenerating it next time you run make. It will only regenerate the files corresponding to the %.h files you've edited.
(Oh, and one last thing: When cutting-and-pasting all these things from this answer, make sure you get your tabs in the right places!)
Just use native wildcard function of GNU Make:
HEADERS := $(wildcard $(SUBDIRS:%=%/*.h))