Changing CMakeCache variables from CMakeLists - cmake

I'm very new to CMake and trying to learn it for a project I'm working on. I'm trying to understand the relationship between CMakeCache.txt and CMakeLists.txt.
I know that CMakeLists.txt will generate the CMakeCache.txt file and that it is possible to edit variables in CMakeCache.txt. My question is, is it possible to edit those variables by editing parameters in the CMakeLists.txt file.
My application is this: I want to change the value of CMAKE_SKIP_RPATH:BOOL=NO to CMAKE_SKIP_RPATH:BOOL=YES. Can I do that from CMakeLists.txt?

You can modify value of any variable at CMakeCache.txt from your CMakeLists.txt file. CMake exposes set() function with configurable parameters to achieve that. In particular, you can control validity of your cache variable through CACHE and FORCE options for this function
In your case, put the following statement in your CMakeLists.txt file to achieve the modification you want
set(CMAKE_SKIP_RPATH YES CACHE BOOL "Skip RPATH" FORCE)
Using CACHE option will let you add a cache variable if not exists. Using FORCE option will let you override value of existing cache variable at CMakeCache.txt. For detailed description about the parameters, please look at the link mentioned above

Related

How to force CMake's target_include_directories() to use absolute path

How do I force CMake's function target_include_directories() to treat the value as an absolute path?
For example, I want this line of code:
target_include_directories(foobar PRIVATE "%FOOBAR_INCLUDE%")
to simply add %FOOBAR_INCLUDE% to the list of include directories.
However, what we actually get is c:\path\to\foobar\%FOOBAR_INCLUDE%.
I know that I could do
target_include_directories(foobar PRIVATE "$ENV{FOOBAR_INCLUDE}")
but that's not what I want. That would expand the value of the environment variable and insert the current setting of the FOOBAR_INCLUDE value.
We need for it to simply push the environment variable, and then during development the developers will change the value of FOOBAR_INCLUDE manually without having to re-run CMake each time.
It is not possible to add something that looks like a relative directory (i.e. "%FOOBAR_INCLUDE%") to the include directories this way. CMake will always try to manipulate these into absolute paths. This is more-or-less stated in the include_directories documentation:
Relative paths are interpreted as relative to the current source directory.
but applies to the target_include_directories() command as well.
Even if you try to circumvent this, and set the INCLUDE_DIRECTORIES property of the target manually:
set_target_properties(foobar PROPERTIES
INCLUDE_DIRECTORIES "%FOOBAR_INCLUDE%"
)
CMake will throw an error during the generation stage:
CMake Error in CMakeLists.txt:
Found relative path while evaluating include directories of "foobar":
"%FOOBAR_INCLUDE%"
You could compromise, providing a full path, but allowing the %FOOBAR_INCLUDE% variable to stay:
target_include_directories(foobar PRIVATE "C:/%FOOBAR_INCLUDE%")
but this ties you and your fellow developers to the C: drive.
I would recommend following the approach you suggested, using an environment variable:
target_include_directories(foobar PRIVATE "$ENV{FOOBAR_INCLUDE}")
or creating a FOOBAR_INCLUDE CMake cache variable that can be populated by each developer before they re-run CMake. If each developer's environment is different, CMake should be re-configured to match that environment.
You can trick CMake into accepting literal values through generator expressions
target_include_directories(foobar PRIVATE $<1:%FOOBAR_INCLUDE%>)
This, however, won't work as CMake will generate an error about the path not being absolute.
Luckily its an include directory, so therefore you can try to add the include flag manually:
target_compile_definitions(foobar PRIVATE -I%FOOBAR_INCLUDE%)

How to ingest property value to cpack-wix without need for running cmake again?

I am using cmake and cpack and wix to build and deploy my project. The installer has some properties that user can enter via GUI or MSI-command-line options.
I set default property values in my CMakeLists.txt using:
set(CPACK_WIX_PROPERTY_<PROPERTY> <value>)
The problem is that if I change these values, I should rerun cmake command before cpack command.
I am looking for a way to change default value of these properties without need for rerunning cmake.
I tried adding additional wxs files using CPACK_WIX_EXTRA_SOURCES or patching generated files with additional xml files using CPACK_WIX_PATCH_FILE, but couldn't find the right code to put in wxs or xml files to accomplish my goal.
I tried The SetProperty command and found out its behavior is not easy to control, I gave up when I saw the user provided values don't replace the initial values and suggested solution at https://web.archive.org/web/20180205001358/http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/Unable-to-override-SetProperty-value-with-Edit-Control-value-td7591569.html didn't work. I hope there is a simple way, but even a complex answer using SetProperty is allright.
I am looking for a way to change default value of these properties without need for rerunning cmake.
A script specified in CPACK_PROJECT_CONFIG_FILE variable is the one, which affects on CPack, but which changing doesn't require cmake to re-run. So you may place setting of CPACK_WIX_PROPERTY_<PROPERTY> here: Changing this setting would require only to re-run CPack without re-run cmake on the main project.
Also, when the script specified in CPACK_PROJECT_CONFIG_FILE variable is parsed, CPACK_GENERATOR variable contains the exact CPack generator which is currently processed. This opposites to behavior of the variable inside CMakeLists.txt, when it contains a list of generators.

Is it possible to read the value of CMAKE_INSTALL_PREFIX variable in postinst?

Just wanted to ask if it is possible to read the value of CMAKE_INSTALL_PREFIX variable in postinst script? The goal is to have postinst script to read a file in ${CMAKE_INSTALL_PREFIX}/share/myapp folder and, based on the content of the file read, to generate a file in ${CMAKE_INSTALL_PREFIX}/etc/myapp folder. I'd like to avoid relying on absolute paths.
Thank you in advance!
Edit
Calling env from postinst gives good information:
DPKG_MAINTSCRIPT_DEBUG=0
DPKG_COLORS=never
DPKG_MAINTSCRIPT_NAME=postinst
DPKG_MAINTSCRIPT_PACKAGE=myapp
DPKG_RUNNING_VERSION=1.19.0.5
DPKG_FRONTEND_LOCKED=true
DPKG_ROOT=
DPKG_MAINTSCRIPT_ARCH=armhf
DPKG_ADMINDIR=/var/lib/dpkg
DPKG_MAINTSCRIPT_PACKAGE_REFCOUNT=1
DPKG_ROOT is probably what I need. It seems that CMAKE_INSTALL_PREFIX is not related to postinst.
Generally speaking at the moment of execution postinst there is no CMake variables (and they definitely never be in the env output). So, the way to do what you want is to generate your postinst script (from postinst.in file) using configure_file function. In the template file you can refer CMake variables, so being rendered your script would contain "hardcoded" literals instead. And that is quite normal.
But, take in account the following:
cpack uses CPACK_PACKAGING_INSTALL_PREFIX variable

Code generator generating its own CMake files and targets

Let's assume I have a script that generates a set of source files forming a target I want to link against in a CMakeLists.txt. If the file names are known to the latter then the usual add_custom_target() and add_custom_command() commands will make it possible to use the generated files as target sources.
Let's assume, though, that only the generator script knows the file names and locations. How can a target library be generated so that the parent CMakeLists.txt can link against it without its knowing the actual file names?
Note that the dependency topic isn't in this question's scope as the script knows itself when to regenerate or not. It's not the finest use of CMake, but it's sufficient in this use case.
Idea #1
The script also generates a generated.cmake file included by the parent one using include(generated.cmake). Problem: CMake doesn't find generated.cmake as it isn't existing at configuration time.
Idea #2
Similar to idea #1, but the script is called with the execute_process() so that generated.cmake is present at configuration time. Problem: The script is not called anymore at subsequent builds, thus ignoring possible changes to its input.
Idea #3
The script passes back a list of targets and files that is somehow considered by the parent CMakeLists.txt. So far I couldn't find a way to do so.
The solution I came with is eventually a mixture of all three ideas.
Solution to idea #1's problem
execute_process() actually ensures that generated_targets.cmake is present at configure time.
Solution to idea #2's and #3's problems
As stated in this answer to "Add dependency to the CMake-generated build-system itself", the CMAKE_CONFIGURE_DEPENDS directory property can be edited to add files whose touching re-triggers the configure step.
The key success factor is that this property can be set after the initial execute_process() call so that the script can identify and list its input dependencies (in an output file) that are then added to CMAKE_CONFIGURE_DEPENDS, hence also solving the input dependency problem.
Resulting pseudo code
# The script generates:
# - <output_dir>/cmake/input_files
# - <output_dir>/cmake/generated_targets.cmake
execute_process(
COMMAND myScript
--output-dir ${CMAKE_CURRENT_BINARY_DIR}/generated
)
# Mark the input files as configure step dependencies so that the execute_process
# commands are retriggered on input file change.
file(STRINGS ${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/input_files _input_files)
set_property(
DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS
${_input_files}
)
# Add the generated CMake targets.
include(${CMAKE_CURRENT_BINARY_DIR}/generated/cmake/generated_targets.cmake)

cmake add_subdirectory with other cmake filename than CMakeLists.txt

CMake documentation states that when add_subdirectory is executed cmake looks for CMakeLists.txt in the directory. Is there any way to change the name of makefile? For example, if I have two cmake files for two completely different configurations and don't want to mix everything in one.
Of course I can create CMakeLists.txt and include something else in it depending on configuration, but I'm just curious if it's possible to make add_subdirectory look for make file with arbitrary name
No, there is no way to do that. The file name CMakeLists.txt is unconfigurably hard-coded in CMake itself. Your best option is, as you say, create a "signpost" CMakeLists.txt file which will just include() the real content based on whatever logic you need.
I know this question is old but I'll answer anyway in case it helps someone. Per the book "Professional CMake" 3rd edition, you should use
include(fileName [OPTIONAL] [RESULT_VARIABLE myVar] [NO_POLICY_SCOPE])
"include() expects the name of a file to read in, whereas add_subdirectory() expects a directory and will look for a CMakeLists.txt file within that directory. The file name passed to include() typically has the extension .cmake, but it can be anything." pg 56.
There are other differences between add_subdirectory() and include() to be mindful of so I would suggest getting the book and giving it a read.