Confused about CMake's cached variable setting priority - caching

I'm confused about CMake's cached variables:
Case 1: CACHE + FORCE
set(CMAKE_CXX_FLAGS "myflags" CACHE STRING "" FORCE)
First CMake run: "myflags" appears in the CMakeCache.txt file as intended.
Command line options: command line options do not override "myflags" - seems like FORCE has higher priority than command line -D...="..." arguments. This is not desired - I would like command line arguments to override "myflags".
Case 2: only CACHE
set(CMAKE_CXX_FLAGS "myflags" CACHE STRING "")
First CMake run: nothing appears in the CMakeCache.txt file. I want"myflags" to appear for the first run.
Command line options: command line have priority over "myflags".
Am I correct about my conclusions? Or do "default variables" such as CMAKE_CXX_FLAGS behave differently?
Is there a way to have "myflags" written in the CMakeCache.txt file during the first CMake run (when CMake wasn't run previously in this folder)?
I'd like to set "myflags" during the first CMake run in the cache, then allow the user to override it using the command line.
If I use FORCE, the user can't override it via command line.
If I don't use FORCE, "myflags" isn't written in the cache file during the first run.

This is consistent with the behaviour explained in the documentation:
Normally, set(...CACHE...) creates cache variables, but does not modify them. If FORCE is specified, the value of the cache variable is set, even if the variable is already in the cache. This should normally be avoided, as it will remove any changes to the cache variable’s value by the user.
CMAKE_CXX_FLAGS is present in the cache even without set(CMAKE_CXX_FLAGS ... CACHE ...) in your CMakeLists.txt, because CMAKE_CXX_FLAGS variable is already set during compiler flags initialization.

Related

Prepending custom dirs ($ZPFX/{include,libs}) to CPP..../LDFLAGS with use of config.site file of autotools?

I'm using a $CONFIG_SITE set to $ZPFX/share/config.site file containing:
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
where $ZPFX variable is my custom user prefix, similar to ~/.local.
Now, the problem is that the system iconv.h (under path /usr/include) isn't found because of this, as only the above pre-set (with use of config.site) -I$ZPFX…/-L$ZPFX… are being passed to the test program, as the following lines from config.log are showing:
configure:21831: gcc -o conftest -g -O2 \
-I/home/q/.local/share/zinit/polaris/include \
-L/home/q/.local/share/zinit/polaris/lib \
conftest.c -lxml2 -liconv >&5
/usr/bin/ld: cannot find -liconv
collect2: error: ld returned 1 exit status
($ZPFX is expanded to its value, which is: /home/q/.local/share/zinit/polaris)
The Question: how to append (prepend) any custom ($ZPFX/… in my case) directories to CPPFLAGS/LDFLAGS, preserving their default values? So that my custom libraries are only given higher precedence, and not exclusivity?
What I've tried
As it can be seen, I've tried to prepend to the flags by appending any occurred values at the time of sourcing the config.site file, by "…$CPP…/$LDFLAGS" :
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
However this has no effect.
I'm also waving between not-appending and appending any typically used system-libraries paths: /usr/include and /usr/lib{,64}, however I don't like the idea, because some system might use e.g.: /opt/… for main prefix, making such hack not working at all.
The documentation explains how configure scripts use CONFIG_SITE. The parts most relevant to your question are near the beginning:
If the environment variable CONFIG_SITE is set, configure uses its
value as a space-separated list of shell scripts to read [...].
Otherwise, it reads the shell script prefix/share/config.site if it
exists, then prefix/etc/config.site if it exists. [...]
Site files can be arbitrary shell scripts
You ask:
how to append (prepend) any custom ($ZPFX/… in my case) directories
to CPPFLAGS/LDFLAGS, preserving their default values? So that my
custom libraries are only given higher precedence, and not
exclusivity?
You need to read only a little between the lines to recognize that the mechanism by which configure scripts read site defaults must be via the . command. That the files may contain arbitrary shell code and that they can set shell variables within configure implies that they are going to be parsed and executed as shell code.
The docs also say what configure does by default when you do not provide CONFIG_SITE, so your site config can do that, too, if you wish. And that's what I would do, to start. Specifically, add this at the beginning of $ZPFX/share/config.site:
test -r "${prefix}/share/config.site" && . "${prefix}/share/config.site"
test -r "${prefix}/etc/config.site" && . "${prefix}/etc/config.site"
Now you have the same settings that configure would get when you don't define CONFIG_SITE at all. What remains is to insert your own additional settings, and the code already presented in the question ought to be fine for that:
CPPFLAGS="-I$ZPFX/include $CPPFLAGS"
LDFLAGS="-L$ZPFX/lib $LDFLAGS"
Additionally, you write:
I'm also waving between not-appending and appending any typically used
system-libraries paths: /usr/include and /usr/lib{,64}, however I
don't like the idea, because some system might use e.g.: /opt/… for
main prefix, making such hack not working at all.
I don't like that idea either.
In the first place, /usr/include, /usr/lib, etc. are not just commonly used, they are typical toolchain defaults. You pretty much never need to explicitly specify toolchain defaults, and trying to do so is more likely to cause harm than good. For example, it could cause breakage in cases such as you posit, where the defaults for the toolchain actually being used are different from the usual ones.
But in the second place, your remarks convey an incorrect perspective on what you're doing with site defaults. These are site-specific, which may mean machine specific or may mean more broadly specific to a group or organization, but any way around, you can set only your own site defaults, not those of other sites.
And that leads me to one final point: the site configuration is part of your site, not part of your project. Hopefully this is not a point of confusion for you, but I want to be sure it is clear. You should not be planning to distribute your site configuration file outside your own site, nor to rely on people wanting to build your project at other sites specifically to use a site configuration file to inject build settings.

Get CMake to declare a target phony

I want to generate some compile time constants. The first answer to another question gets me quite close. From my CMakeLists.txt:
add_library(${PROJECT_NAME} STATIC ${CXX_SRCS} compile_time.hpp)
add_custom_command(OUTPUT compile_time.hpp
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/compile_time.cmake)
This works in the sense that the first time I run make, it generates compile_time.hpp, so that the values of the variables are defined when I run make and not cmake. But compile_time.hpp is not remade when I rerun make or even cmake to redo the makefiles.
How can I make the target compile_time.cpp be marked as phony so that it is always remade? I tried
add_custom_target(compile_time.hpp)
to no effect.
add_custom_target creates a "phony" target: It has no output and is always built. For make some target depended from the "phony" one, use add_dependencies() call:
add_custom_target(compile_time
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/compile_time.cmake
)
# Because we use *target-level* dependency, there is no needs in specifying
# header file for 'add_library()' call.
add_library(${PROJECT_NAME} STATIC ${CXX_SRCS})
add_dependencies(${PROJECT_NAME} compile_time)
Library's dependency from the header compile_time.h will be detected automatically by headers scanning. Because script compile_time.cmake updates this header unconditionally, the library will be rebuilt every time.

Command-line variables - in makefile - expand to weird values

From the docs:
Target-specific variables have the same priority as any other
makefile variable. Variables provided on the command line (and in the
environment if the '-e' option is in force) will take precedence.
Specifying the 'override' directive will allow the target-specific
variable value to be preferred.
So, a simple makefile, like:
# A pattern-specific variable assignment.
% : foo += file
all : x ;
# Target is a double-colon w/o dependencies, so Make will ALWAYS run its commands.
x ::
#echo '$(foo)'
Running, we get:
# Override makefile-level variables, with a command-line assignment.
$ make foo=cmd
cmd cmd cmd
# Set the value in the environment, And tell Make to prefer it over any makefile-level definitions.
$ foo=env make --environment-overrides
env file file
Returning now, to the quote above, from the documentation:
Variables provided on the command line (and in the environment if the '-e' option is in force) will take precedence.
It seems, that using either:
Command-line assignment.
Environment-set variables, AND using -e (--environment-overrides).
Have both the same effect, i.e. overrides the file-level (makefile) variable.
But, the results differ greatly. Remember that the value given in the command-line was: cmd, and the value given in the environment was: env.
Now, compare the values, given for a command-line override vs. an environment override:
cmd cmd cmd (for command-line override).
env file file (for environment override).
So, whereas for command-line, Make repeats the same value, i.e. cmd, 3 times, for environment-override, the situation is different. That is, Make will "repeat" the environment-level value: env only 1 time, and then repeats - none other - than the overridden file-level value: file.
Now, not only is the situation completely different for an "override" from command-line vs. an "override" from the environment, which is strange by itself, the problem here is much bigger.
Since, Make rules to give "priority" for a command-line (or environment) value, why does it insist to append "other" values (as in the case of environment-override, where Make appends "file file"), or in the case of a command-line override (where Make repeats the same value ***3* times). Seriously?
How does it make sense at all? And what is the justification for these inconsistent and strange results?
I believe the answer here is related to the answer to this other question of yours. (And possibly a bug in the env override version.)
The global variables and the target-specific variables are distinct variables.
The cmd cmd cmd result is because when you write %: foo += file make stores that as an addition to the current value of variable foo of the target-specific value of the variable foo which is file.
However, when you set foo on the command line make overrides the value of the target-specific variable foo to be cmd instead of file. So when make concats the variable each time it gets cmd cmd cmd.
That explanation should, I think, get you env env env then and I'm not sure why it doesn't. This could be a bug or it could be some other detail about how env override variables and target-specific variable values work. I'm not sure.
(Check the output of make -p for both these cases to see what I mean about the target-specific variable's value.)

How to make gcc uses march=native as default?

Is there a way to change the specs file so that it will pass -march=native if nothing is specified in command line?
Related things in the default specs file is:
*cc1:
%(cc1_cpu)
*cc1_cpu:
%{march=native:%>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)}} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
I am not sure how specs works. Simply specifying -march=native before or after %(cc1_cpu) doesn't work. However, this line does take effect because GCC will report error if I put -something_wierd instead of -march=native.
Another thing I noticed is if I put %{march=i386:-something_wierd} before %(cc1_cpu), gcc reports error so looks like -march=i386 is always passed in if nothing is specified, so is there a way to distinguish between nothing specified and -march=i386 in specs file?
BTW, what does %> do? Seems like it is not specified in the documentation.
I am using MinGW's gcc-4.6.2.
Referring to your last question: The gcc 4.6.1 sources (gcc/gcc.c) contain the following comment on %>:
%>S Similar to "%<S", but keep it in the GCC command line.
For the sake of completeness following the comment for %< form the same file:
%<S remove all occurrences of -S from the command line.
Note - this command is position dependent. % commands in the
spec string before this one will see -S, % commands in the
spec string after this one will not.
To answer the first question in short: yes, but ....
... the only generic solution I found has the significant drawback that the -march option will be ignored, so every build is done as if -march=native had been specified. Anyhow there is a workaround to that.
1 The solution (without workaround)
Create a specs-file called let's say specs.nativealways containing:
*cc1_cpu:
%<march=* -march=native %>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
When using the specs-file (for example by invoking gcc with the option -specs=specs.nativealways) the build will be done as if -march=native was specified (with the mentioned drawback that any occurrence of option -march=<arch> would have simply been ignored).
2 The workaround
To still by able to override the newly configured default behavior one can use a modified version of the specs-file described above, introducing a new option called -myarch using the same syntax as -march (except for -myarch=native, which won't work, which does not metter as native now is the default).
The modfied specs-file looks like this:
*cc1_cpu:
%<march=* %{myarch=*:%<myarch* -march=%* ; :-march=native %>march=native %:local_cpu_detect(arch) %{!mtune=*:%>mtune=native %:local_cpu_detect(tune)}} %{mtune=native:%>mtune=native %:local_cpu_detect(tune)}
PS: This has been tested with with gcc 4.6.2 on Linux, but should work on MinGW.
While not a direct answer to your question, you can reach a very similar effect by defining CFLAGS and CXXFLAGS in your shell's initialization file. 99% of the Makefiles are sufficiently standard to pick up the environment values and pass the flags to gcc.
*cc1_cpu:
+ %{!march*:-march=native}

Firefox make file

I want to backtrace the makefile for firefox so that I can get the final gcc command that is used to compile the c++ files. How can I do that?
If you find a line in there that begins with "# $(CXX)" or "# g++", then change the line to "$(CXX)" or "g++" -- in other words, delete the "#" symbol from the line. When an "#" symbol appears at the beginning of a command in a Makefile, it causes Make to not echo the command before executing it. Deleting the "#" symbol will cause the expanded form of the line to be echoed before the command is invoked.
I haven't looked at Firefox's makefile, so it is more than possible that they are using predefined pattern rules for building the code, in which case you won't see any lines beginning with "$(CXX)" . If that is the case, you will need to override the rules, so that the default build rules echo the commands before executing them.
For more information on overriding Makefile pattern build rules, see this link:
http://www.gnu.org/software/make/manual/make.html#Pattern-Rules
The usual stunt for this is to replace gcc with a program that reads the gcc command line,
store it in some log file so it can be inspected, and then launches gcc with the command line. You can do this by replacing "gcc.exe" in your development directories by this stepping stone program.
Here's the make rule that compiles C++ files:
http://hg.mozilla.org/mozilla-central/annotate/c1ab8650e0ce/config/rules.mk#l1391
If all you want to do is replace the compiler, you can (in your mozconfig, or on the configure commandline) set CXX="whatever".
Can you redirect the output of make to a file, then use a text editor to search for the line of interest?

Resources