CMake override cached variable using command line - caching

As I understand it, when you provide a variable via the command line with cmake (e.g. -DMy_Var=ON), that variable is stored inside the cache. When that variable is then accessed on future runs of the CMake script, it will always get the value stored inside the cache, ignoring any subsequent -DMy_Var=OFF parameters on the command line.
I understand that you can force the cache variable to be overwritten inside the CMakeLists.txt file using FORCE or by deleting the cache file, however I would like to know if there is a nice way for the -DMy_Var=XXX to be effective every time it is specified?
I have a suspicion that the answer is not to change these variables within a single build but rather have separate build sub-dirs for the different configs. Could someone clarify?

I found two methods for changing CMake variables.
The first one is suggested in the previous answer:
cmake -U My_Var -D Mu_Var=new_value
The second approach (I like it some more) is using CMake internal variables. In that case your variables will be still in the CMake cache, but they will be changed with each cmake invocation if they are specified with -D My_Var=.... The drawback is that these variables would not be seen from GUI or from the list of user's cache variables. I use the following approach for internal variables:
if (NOT DEFINED BUILD_NUMBER)
set(BUILD_NUMBER "unknown")
endif()
It allows me to set the BUILD_NUMBER from the command line (which is especially useful on the CI server):
cmake -D BUILD_NUMBER=4242 <source_dir>
With that approach if you don't specify your BUILD_NUMBER (but it was specified in previous invocations), it will use the cached value.

You could use
CMake -UMy_Var -DMy_Var=new_value
see documentation https://cmake.org/cmake/help/v3.9/manual/cmake.1.html
I hope this helps.

Find this post by coincidence.
It seems the behavior described by OP isn't the case for CMake 3.12 onwards. For previous releases, I didn't make some tests so cannot confirm.
Variables provided by -D on command line are stored in CMakeCache.txt. They can be overridden, even the same variable is repeatedly provided and the last one is set to the value for that variable.
For example, a very easy CMake script
message(STATUS "FOO = " ${FOO})
$ cmake -DFOO=123 -DFOO=321 .. # the last one takes effect
-- FOO = 321
-- Configuring done
-- Generating done
-- Build files have been written to: xxx
$ cmake .. # cache is remembered
-- FOO = 321
-- Configuring done
-- Generating done
-- Build files have been written to: xxx
$ cmake -DFOO=changed .. # override it
-- FOO = changed
-- Configuring done
-- Generating done
-- Build files have been written to: xxx

Related

How can I refer to the first file in an .xcfilelist within an Xcode build script?

How can I refer to the first file in an .xcfilelist within an Xcode build script?
If I list the files separately (instead of using an .xcfilelist) then I can use SCRIPT_OUTPUT_FILE_0 of course. However if I use a .xcfilelist instead, then how can I reference that first output file?
The only reason we want to use the .xcfilelist in the first place is so Xcode doesn't re-run the script and rebuild the module every single time we run a compile. However that's exactly what it's doing... it seems to be ignoring what's specified in the output file list's .xcfilelist and always regenerating those files and then recompiling them even when nothing has changed.
Seems like an Xcode bug but figured maybe we could compare the modification times at the beginning of the script by referencing the first file in the file list, but I cannot seem to find a way to do that.
If you want to iterate over all lines in all xcfilelists then this simplistic script can do it:
for index in $(seq $SCRIPT_INPUT_FILE_LIST_COUNT); do
# 1 => `SCRIPT_INPUT_FILE_LIST_0`
filelist=SCRIPT_INPUT_FILE_LIST_$((index-1))
# `SCRIPT_INPUT_FILE_LIST_0` => value in $SCRIPT_INPUT_FILE_LIST_0
filelist_path=${!filelist}
while read -r file_path; do
echo "${file_path}"
done <$filelist_path
done
It will dynamically construct the SCRIPT_INPUT_FILE_LIST_0, SCRIPT_INPUT_FILE_LIST_1, etc. values and access them from the environment vars passed to the script by Xcode.

autoconf: how do I substitute the library prefix?

CLISP's interface to PARI is configured with the configure.in containing AC_LIB_LINKFLAGS([pari]) from lib-link.m4.
The build process also requires the Makefile to know where the datadir of PARI is located. To this end, Makefile.in has
prefix = #LIBPARI_PREFIX#
DATADIR = #datadir#
and expects to find $(DATADIR)/pari/pari.desc (normally
/usr/share/pari/pari.desc or /usr/local/share/pari/pari.desc).
This seems to work on Mac OS X where PARI is installed by homebrew in /usr/local (and LIBPARI_PREFIX=/usr/local), but not on Ubuntu, where PARI is in /usr, and LIBPARI_PREFIX is empty.
How do I insert the location of the PARI's datadir into the Makefile?
PS. I also asked this on the autoconf mailing list.
PPS. In response to #BrunoHaible's suggestion, here is the meager attempt at debugging on Linux (where LIBPARI_PREFIX is empty).
$ bash -x configure 2>&1 | grep found_dir
+ found_dir=
+ eval ac_val=$found_dir
+ eval ac_val=$found_dir
You are trying to use $(prefix) in an unintended way. In an Autotools-based build system, the $(prefix) represents a prefix to the target installation location of the software you're building. By setting it in your Makefile.in, you are overriding the prefix that configure will try to assign. However, since you appear not to have any installation targets anyway, at least at that level, that's probably more an issue of poor form than a cause for malfunction.
How do I insert the location of the PARI's datadir into the Makefile?
I'd recommend computing or discovering the needed directory in your configure script, and exporting it to the generated Makefile via its own output variable. Let's take the second part first, since it's simple. In configure.in, having in some manner located the wanted data directory and assigned it to a variable
DATADIR=...
, you would make an output variable of that via the AC_SUBST macro:
AC_SUBST([DATADIR])
Since you are using only Autoconf, not Automake, you would then manually receive that into your Makefile by changing the assignment in your Makefile.in:
DATDIR = #DATADIR#
Now, as for locating the data directory in the first place, you have to know what you're trying to implement before you can implement it. From your question and followup comments, it seems to me that you want this:
Use a data directory explicitly specified by the user if there is one. Otherwise,
look for a data directory relative to the location of the shared library. If it's not found there then
(optional) look under the prefix specified to configure, or specifically in the specified datadir (both of which may come from the top-level configure). Finally, if it still has not been found then
look in some standard locations.
To create a configure option by which the user can specify a custom data directory, you would probably use the AC_ARG_WITH macro, maybe like this:
AC_ARG_WITH([pari-datadir], [AS_HELP_STRING([--with-pari-datadir],
[explicitly specifies the PARI data directory])],
[], [with_pari_datadir=''])
Thanks to #BrunoHaible, we see that although the Gnulib manual does not document it, the macro's internal documentation specifies that if AC_LIB_LINKFLAGS locates libpari then it will set LIBPARI_PREFIX to the library directory prefix. You find that that does work when the --with-libpari option is used to give it an alternative location to search, so I suggest working with that. You certainly can try to debug AC_LIB_LINKFLAGS to make it set LIBPARI_PREFIX in all cases in which the lib is found, but if you don't want to go to that effort then you can work around it (see below).
Although the default or specified installation prefix is accessible in configure as $prefix, I would suggest instead going to the specified $datadir. That is slightly tricky, however, because by default it refers to the prefix indirectly. Thus, you might do this:
eval "datadir_expanded=${datadir}"
Finally, you might hardcode a set of prefixes such as /usr and /usr/local.
Following on from all the foregoing, then, your configure.in might do something like this:
DATADIR=
for d in \
${with_pari_datadir} \
${LIBPARI_PREFIX:+${LIBPARI_PREFIX}/share/pari} \
${datadir_expanded}/pari \
/usr/local/share/pari \
/usr/share/pari
do
AS_IF([test -r "$[]d/pari.desc"], [DATADIR="$[]d"; break])
done
AS_IF([test x = "x$DATADIR"], [AC_MSG_ERROR(["Could not identify PARI data directory"])])
AC_SUBST([DATADIR])
Instead of guessing the location of datadir, why don't you ask PARI/GP where its datadir is located? Namely,
$ echo "default(datadir)" | gp -qf
"/usr/share/pari"
does the trick.

How to input a parameter in a custom target with cmake

I have a custom target:
add_custom_target(
create-po
COMMAND ${MSGINIT} --no-translator -i "${PROJECT_SOURCE_DIR}/data/${PACKAGE}.pot" - "${PROJECT_SOURCE_DIR}/po/es.po" -l es_MX.utf8
)
so, is invoked like this:
# make create-po
my idea is to change it to something like this:
# make create-po "es"
so, any user can create a custom localed po file. I don't know the word exactly for this, but I'd like to add a parameter in the target name..is it posible with cmake? Thanks
After so long time I found this question for the same reason: Can I use CMake to initialize a .po file if I want to add a new translation? I expect to use it only once in a while for my project, so make the build system do it seems more comfortable to me than find out all the required options and paths every time.
I ended up with the following CMake snippet:
set(INIT_LANG CACHE STRING "give a locale here to create a target which initializes a related .po file")
IF(INIT_LANG)
add_custom_target(
create-po-${INIT_LANG}
... # integrate INIT_LANG in your command
)
ENDIF(INIT_LANG)
Then, if you want to initialize a new translation file, call (assuming your build dir in under the project root):
# cmake -DINIT_LANG=es_MX.utf8 ..
... and you should get a corresponding make target:
# make create-po-es_MX.utf8
Yes, it's not as straight-forward as the OP's idea/expectation (and mine as well), but users can create new .po files by themselves (of course, this will be documented properly for them in the project ;) ).

How to load addtional parameter in CMake?

I want to build a project #local dictionary.
And in 'CMakeLists.txt' the project A want to find another library B using 'FIND_PACKAGE' command.
The problem is that library B can be found in system directory while I rebuild it # my local directory, so how can I control that case by inputting a additional parameter when typing 'cmake .'?
You can give specify variable values using CMake's -D command line option.
Note that the variable in question has to be stored in the cache for this to work, as the command line simply sets a cache entry and local variables hide cache variables of the same name.
cmake -DMY_AWESOME_VARIABLE=Foo <path_to_source>
CMakeLists.txt
[...]
# set a default value that will be used if no option is given on the command line
set(MY_AWESOME_VARIABLE "Default value" CACHE STRING "")
# this line will output the current value from cache; so either the default
# value or whatever was given last on the command line
message(${MY_AWESOME_VARIABLE})
# local variables hide cache entry, so the next message will always print "Local"
set(MY_AWESOME_VARIABLE "Local")
message(${MY_AWESOME_VARIABLE})
you could temporarily change the PATH environment variable to only your local bin aud or usr... by running cmake with:
PATH=~/bin:~/usr:~/usr/bin cmake
But then you have to put all the required executables in that/those folders.

What is the `#Name#` in command line?

I'm looking for Tsung source code. There is a line like following in file tsung.sh.in:
ERL_OPTS=" $ERL_DIST_PORTS -smp auto +P $MAX_PROCESS +A 16 +K true #ERL_OPTS# "
What does the #ERL_OPTS# mean?
This seems to be something that gets substituted by autoconf during the build process.
Generally, a .in file gets preprocessed by some build script. Autoconf uses #IDENTIFIER# to indicate the place where the actual value has to be put in. The preprocessed version loses the .in extension, thus generating tsung.sh in this particular case.

Resources