CMake: print root project name using cmake commandline - cmake

Is it possible to print project name value of a CMake project using cmake.exe?
for example:
cmake -LA CMakeLists.txt | grep CMAKE_INSTALL_PREFIX
to get the install prefix configured for the project.
Is there any way similar to get CMAKE_PROJECT_NAME which is defined in project('xyz')?

The variable CMAKE_PROJECT_NAME is not a cached one, so it cannot be printed by running cmake -LA.
Using variable CMAKE_PROJECT_INCLUDE it is possible to define a hook for project() calls. That hook could just print a project name.
For example, consider such script project_hook.cmake:
message(STATUS "Project name is ${PROJECT_NAME}")
You could configure a CMake project with
cmake -DCMAKE_PROJECT_INCLUDE=</path/to/project_hook.cmake> </path/to/source/dir> | grep -m1 "Project name is"
so you will get the line
Project name is <...>
for the first project() call encountered in the CMake project.
This approach works for CMake 3.15 or newer.

Related

Cmake get/query/print build settings on the command line?

Let's assume I have a Cmake C project, and I have something like this in the project:
project(my_project C CXX ASM)
set(my_executable_sources
main.c
file_one.c
)
set(my_executable_sources ${my_executable_sources} file_two.c)
add_executable(my_executable
${my_executable_sources}
file_three.c
)
Let's assume I'm in the ./build subfolder, and cmake ../ -G "Unix Makefiles" has passed successfully.
Can I somehow query build information from the command line using cmake?
For instance, I'm interested here in the final list of source files for my_executable; is there a command that would easily retrieve them? Say, like the following pseudocode:
$ cmake --pseudo-query-build --project="my_project" --target="my_executable" --query="source_files"
my_executable source files:
main.c
file_one.c
file_two.c
file_three.c
I don't see any cmake-generator-independent way of achieving this and even if you know the generator in use the project files generated.
You could modify your project to include a custom target that prints the sources though:
add_custom_target(print_my_executable_sources COMMAND ${CMAKE_COMMAND} -E echo "$<TARGET_PROPERTY:my_executable,SOURCES>" COMMAND_EXPAND_LISTS)
this allows you to use
cmake --build <binary_dir> [--config <configuration>] --target print_my_executable_sources
to print the sources, even if generator expressions are used in the sources.
Note: This does print all files in a single line; to get all the file names on separate lines, you could instead run cmake with the -P option passing the soures via -D and add logic to print one file name per line in the cmake script file.
Alternatively setting the CMAKE_EXPORT_COMPILE_COMMANDS variable to True during configuration could result in the generation of json files that would allow for the extraction of the information, but you'd need a json parser to extract the info. Furthermore this approach only works for the Makefile and Ninja CMake generators. Also I'm not sure you can tell which target a source file belongs to in all cases.
Start by obtaining the target's sources via this line (after add_executable):
get_target_property(MY_TARGET_SOURCES my_executable SOURCES)
And then proceed with a simple line at the end of the file (after add_executable)
message(STATUS ${MY_TARGET_SOURCES})
EDIT: For a full list of available target properties refer to this link.
EDIT2: As I've noticed now that you probably intend to just use it within the CLI, then for my solution you would also have to encapsulate it with a if/endif that checks for a definition e.g. if(SOURCES_DEBUG_INFO) and then run it with -DSOURCES_DEBUG_INFO=TRUE

How to write CMakeLists.txt with NOT using 'MSBuild.exe' on windows? [duplicate]

This question already has answers here:
cmake: Selecting a generator within CMakeLists.txt
(5 answers)
Closed 3 years ago.
I'm trying to write the CMakeLists.txt for building a custom targets only project.
That is, it's not for the usual C/C++ project; all build recipes are provided using ADD_CUSTOM_COMMAND() and ADD_CUSTOM_TARGET(). The reason why I'm using CMake is to manage dependencies between build target stuffs and utilize the advantages of incremental build.
The problem is, when I execute cmake CMakeLists.txt on Windows cmd.exe, it tries to find Windows SDK or MSBuild.exe -- which are never needed for building targets in the project.
cmd.exe> cmake CMakeLists.txt
-- Selecting Windows SDK version 10.0.18362.0 to target Windows 10.0.17134.
CMake Error at CMakeLists.txt:6 (PROJECT):
Failed to run MSBuild Command:
MSBuild.exe
to get the value of VCTargetsPath:
Cannot find file
-- Configuring incomplete, errors occurred!
See also "CMakeFiles/CMakeOutput.log"
The header of the CMakeLists.txt is:
cmake_minimum_required ( VERSION 3.0 )
set ( CMAKE_GENERATOR "Unix Makefile" )
set ( CMAKE_VERBOSE_MAKEFILE true )
# Project name
project ( "awesome-project" NONE ) # <language>=NONE for skipping compiler check
...
As I mentioned above, all recipes of the build targets are provided in the CMakeLists.txt; neither Windows SDK nor Visual Studio is required.
I think there is some CMake directives for skipping the invocation of MSBuild, but I could not find it. How can I write the CMakeLists.txt in this case?
As the answer here suggests, setting the CMAKE_GENERATOR variable in the CMake file has no effect when running CMake for the first time. CMake will use the default generator on the first attempt, if no generator is provided via the command line or via environment variable. So try adding the command line option -G to specify the generator like this:
cmake -G "Unix Makefiles" .
Then, on subsequent CMake runs, the generator setting will be cached and you no longer need to provide the -G generator option.
As a side note, you can simply provide the path to your top-level CMakeLists.txt file. So if it's in the current directory, you can just use . for the path.
The documentation is pretty explicit The value of this variable should never be modified by project code. A generator may be selected via the cmake(1) -G option, interactively in cmake-gui(1), or via the CMAKE_GENERATOR environment variable.
You can always make a CMake script that runs CMake with the proper options to create the project.
You may want to keep watch on CMAKE_VERBOSE_MAKEFILE because This variable is a cache entry initialized (to FALSE) by the project() command. I wouldn't be surprised if it doesn't work as shown in your script. Instead You'd probably have to add a -D option on the command line to set it. https://bytefreaks.net/programming-2/make-building-with-cmake-verbose

How is cmake finding my llvm cmake configuration?

I am wondering how is cmake finding my llvm cmake configuration if I haven't given it any variable telling it where to find it.
I am an LLVM newcomer. I am building a Hello World LLVM pass. I am on Ubuntu 16.04. My version of LLVM is 8.0.0. My version of CMake is 3.5.1.
This is my /CMakeLists.txt file:
cmake_minimum_required(VERSION 3.1)
project(FunctionDebugger)
find_package(LLVM REQUIRED CONFIG)
include_directories(${LLVM_INCLUDE_DIRS})
add_subdirectory(FunctionDebugger)
set(CMAKE_VERBOSE_MAKEFILE on)
This is the FunctionDebugger/CMakeLists.txt file:
add_library(LLVMFunctionDebugger MODULE
FunctionDebugger.cpp
)
set_target_properties(LLVMFunctionDebugger PROPERTIES
COMPILE_FLAGS "-fno-rtti -std=c++11"
)
I configure and compile like this:
mkdir build && cd build
cmake ..
make
It correctly compiles and links a shared library called libLLVMFunctionDebugger.so. What I don't understand is how cmake could find the package requested in:
# <project-root>/CMakeLists.txt
find_package(LLVM REQUIRED CONFIG)
I am not giving it any path nor I have anything defined in the environment but the path to the LLVM binaries.
I read the CMake documentation, but it says that the find_package looks in folders under CMAKE_PREFIX_PATH. I print that variable with message(STATUS ${CMAKE_PREFIX_PATH}) and the output is empty.
Your set-up looks correct and clearly CMake is finding LLVMConfig.cmake script (i.e. the script that find_package consumes to propagate the necessary CMake variables with LLVM 8 set-up).
On the Ubuntu 16.04 machine that I have access to, LLVMConfig.cmake is located in /usr/lib/llvm-8/lib/cmake/llvm/LLVMConfig.cmake, but there's also a symlink in /usr/lib/llvm-8/cmake/. So the natural questions is: does CMake know that it should look there? The answer is yes. In CMake docs you can see that one of the search paths is:
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
You can verify that usr is on the list of prefixes by printing CMAKE_SYSTEM_PREFIX_PATH. On my machine that's set-up to:
/usr/local;/usr;/;/usr;/usr/local
Finally, you can print LLVM_DIR in your CMake script to check which version/installation of LLVM was picked by find_package. The variable will be empty on the first execution of CMake, but then find_package finds LLVM-8, the variable is set and saved in CMakeCache.txt.
Hope this helps.
EDIT
This answer was tested on Ubuntu 16.04 on which LLVM 8 was installed in the default, system-wide location through apt-get. If you install LLVM 8 elsewhere, then there are various ways of pointing CMake to the right location, see the docs for find_package. Editing the PATH variable is one of them:
Search the standard system environment variables. This can be skipped if NO_SYSTEM_ENVIRONMENT_PATH is passed. Path entries ending in /bin or /sbin are automatically converted to their parent directories:
PATH
Since cmake 3.17, you can use cmake --debug-find <cmake-options> to ask cmake to output a bunch of debugging information on find_* functions. On my machine, it outputs
Standard system environment variables [CMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATH].
/home/jiaqi/Documents/LLVM/llvm-project/build
/home/jiaqi/.local
/home/jiaqi/.yarn
/home/jiaqi/anaconda3
/home/jiaqi/anaconda3/condabin
/usr/local
/usr
/
/usr/games
/usr/local/games
/snap
... outputs omitted...
find_package considered the following locations for LLVM's Config module:
/home/jiaqi/Documents/LLVM/Test/build/CMakeFiles/pkgRedirects/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/Test/build/CMakeFiles/pkgRedirects/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/cmake/LLVMConfig.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/cmake/llvm-config.cmake
/home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
The file was found at
/home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
So, the cmake is using Config mode here and the file is located at /home/jiaqi/Documents/LLVM/llvm-project/build/lib/cmake/llvm/LLVMConfig.cmake
To figure out how cmake finds the LLVMConfig.cmake, take a look at https://cmake.org/cmake/help/latest/command/find_package.html#search-procedure
For step 5, it says the cmake will search the environment variable $PAT, and note that
Path entries ending in /bin or /sbin are automatically converted to their parent directories.
Since I have put the path to llvm executables in $PATH:
$ echo $PATH
/home/jiaqi/Documents/LLVM/llvm-project/build/bin:/home/jiaqi/.local/bin:/home/jiaqi/.yarn/bin:/home/jiaqi/anaconda3/bin:/home/jiaqi/anaconda3/condabin:/home/jiaqi/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
The folder /home/jiaqi/Documents/LLVM/llvm-project/build will be used as prefix. According to https://cmake.org/cmake/help/latest/command/find_package.html#config-mode-search-procedure, the folder <prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/ will be searched.

Display CMake variables without running CMake on a CMakeLists.txt file or manually inspecting config.cmake?

Suppose I have a package called Foo. If I run CMake on a CMakeLists.txt file that contains find_package(Foo), then I can print out the values of variables such as ${Foo_LIBRARIES} and ${Foo_INCLUDES}.
Is there an easy way to display these variables without having to run CMake on a CMakeLists.txt file, and without having to manually inspect the config.cmake file?
You asked: (1) Is there an easy way to display these variables without having to run cmake on a CMakeLists.txt file, and (2) without having to manually inspect the config.cmake file?
I can give you a yes answer to (2) but it does require that you (re)run cmake. But since you can re-run your cmake configure step by simply executing cmake . in the build directory, re-running cmake should not keep you from trying this approach. My answer is given in this SO answer and uses the get_cmake_property command. Here is that code encapsulated into a cmake macro, print_all_variables, so I can use it when debugging my cmake scripts.
macro(print_all_variables)
message(STATUS "print_all_variables------------------------------------------{")
get_cmake_property(_variableNames VARIABLES)
foreach (_variableName ${_variableNames})
message(STATUS "${_variableName}=${${_variableName}}")
endforeach()
message(STATUS "print_all_variables------------------------------------------}")
endmacro()
The macros are invoked with same syntax as cmake functions:
print_all_variables()
To simply print a value, you could do something like this:
message(STATUS "foo include dir: ${foo_INCLUDE}")
where ${foo_INCLUDE} is the value you desire to print.
Note: I'm using cmake > 3.14
Run CMake and have a look at the cache with the ccmake GUI tool. Then you'll get all the variables.
Or run CMake with -LH then you will get all variables printed after configuration.
So I think it is not possible to get the variables without running CMake.
Run cmake in find-package mode. Example to display a package`s include directories:
cmake -DNAME=ZLIB -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=COMPILE --find-package
Example to display the libraries:
cmake -DNAME=ZLIB -DCOMPILER_ID=GNU -DLANGUAGE=C -DMODE=LINK --find-package
The NAME must be set to the package name. You can obtain your COMPILER_ID on this page. LANGUAGE can be C, CXX or Fortran.
I am always suspicious of variables changing values throughout a script somewhere so I like to see the value of a variable at a particular point in the running script. Combining the ideas from both Phil and Aaron B. this is what I'm using:
function(PRINT_VAR VARNAME)
message(STATUS "${VARNAME}: ${${VARNAME}}")
endfunction()
PRINT_VAR("CMAKE_CXX_COMPILER")
Then I can just litter PRINT_VAR statements around like I'm debugging code back in 1980
These variables are generally hardcoded into FindFoo.cmake so that it is not possible to extract them without running the function first. Note that sometimes the value of Foo_LIBRARIES depends on the system configuration, which is unknown until find_package(Foo) is run.

Compiling a CMake project against libraries in a non-standard location

I have two projects using CMake.
The first is a shared library. It compiles and installs fine. Currently, it is still necessary to build 'debug' releases of it. So presently it is installed under ~/localdebug. That folder looks like the root of a filesystem with a 'include' and 'lib' directory. The same concept as '/usr/local'.
The second is a program. It needs to compile and link against my library in ~/localdebug. The CMakeLists.txt file for it looks like this:
cmake_minimum_required(VERSION 2.6)
set(CMAKE_C_FLAGS "-std=gnu99")
#add_definitions(-pg)
find_library(SANDGROUSE_LIB NAMES sandgrouse)
add_library(http_parser http_parser.c)
add_executable(rsva11001adapter main.c rsva11001.c)
target_link_libraries(rsva11001adapter http_parser ${SANDGROUSE_LIB})
I run the following to set up the make files:
cmake --debug-output -DCMAKE_BUILD_TYPE=Debug -DCMAKE_PREFIX_PATH="/home/ericu/localdebug" ..
Based on the CMake wiki, setting DCMAKE_PREFIX_PATH does exactly what I want.
CMAKE_PREFIX_PATH
(since CMake 2.6.0) This is used when searching for include files, binaries, or libraries using either the FIND_PACKAGE(), FIND_PATH(), FIND_PROGRAM(), or FIND_LIBRARY() commands. For each path in the CMAKE_PREFIX_PATH list, CMake will check "PATH/include" and "PATH" when FIND_PATH() is called, "PATH/bin" and "PATH" when FIND_PROGRAM() is called, and "PATH/lib" and "PATH" when FIND_LIBRARY() is called. See the documentation for FIND_PACKAGE(), FIND_LIBRARY(), FIND_PATH(), and FIND_PROGRAM() for more details.
However, when I do a 'make VERBOSE=1' this is what I get:
cd /home/ericu/rsva11001adapter/build/src && /usr/bin/gcc -std=gnu99 -g -o CMakeFiles/rsva11001adapter.dir/main.c.o -c /home/ericu/rsva11001adapter/src/main.c
/home/ericu/rsva11001adapter/src/main.c:19:31: fatal error: sandgrouse/server.h: No such file or directory
compilation terminated.
So, it does not seem that CMake is finding things in CMAKE_PREFIX_PATH. It obviously is not adding -I variables to the compiler invocations either.
An inspection of CMakeCache.txt makes it seem as though it has no idea what the variable is:
// No help, variable specified on the command line.
CMAKE_PREFIX_PATH:UNINITIALIZED=/home/ericu/localdebug
I've been working on this for over an hour. I'm nearly at the point of giving up using CMake if it is this difficult to use a non-standard library with it.
You should instruct CMake to add -I flags when compiling your library:
find_path(SANDGROUSE_INCLUDE_DIR sandgrouse/server.h)
include_directories(${SANDGROUSE_INCLUDE_DIR}
Place these lines before add_library() invocation.