How to set a CMake option() at command line - cmake

I created a CMakeLists.txt that contains the following
project(P4V)
cmake_minimum_required(VERSION 2.6)
option(BUILD_STATIC_LIBS "Build the static library" ON)
option(BUILD_SHARED_LIBS "Build the shared library" ON)
option(BUILD_TESTS "Build test programs" OFF)
include_directories(${CMAKE_SOURCE_DIR}/include)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
set(CMAKE_BUILD_TYPE Release)
add_subdirectory(src)
if(BUILD_TESTS)
add_subdirectory(tests)
endif(BUILD_TESTS)
By default BUILD_TESTS is OFF, how can I turn it ON without CMake GUI, but with cmake command itself?
I tried the following, but it doesn't work
cmake .. -G %1 -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_TESTS=ON

Delete the CMakeCache.txt file and try this:
cmake -G %1 -DBUILD_SHARED_LIBS=ON -DBUILD_STATIC_LIBS=ON -DBUILD_TESTS=ON ..
You have to enter all your command-line definitions before including the path.

An additional option is to go to your build folder and use the command ccmake .
This is like the GUI but terminal based. This obviously won't help with an installation script but at least it can be run without a UI.
The one warning I have is it won't let you generate sometimes when you have warnings. if that is the case, exit the interface and call cmake .

this works for me:
cmake -D DBUILD_SHARED_LIBS=ON DBUILD_STATIC_LIBS=ON DBUILD_TESTS=ON ..

Related

Prohibit cmake build on the top-level source

I would like to prohibit cmake in-source build especially at top-level.
For example prohibited case is cmake -S . -B ., however, I would like to allow cmake -S . -B build
Thus, these following options are not fitted here.
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
I added small script in CMakeLists.txt
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
if("${srcdir}" STREQUAL "${bindir}")
message(FATAL_ERROR "Do not build on the top of the sources")
endif()
It works, but CMakeCache.txt and CMakeFiles are still created. How can I keep my sources clean?
With git, git clean -d -f -x can help me, but I would like to have a solution with cmake itself.
"CMakeCache.txt and CMakeFiles are still created" -- you cannot avoid this with CMake <=3.24, the latest development version at time of writing. You can suggest deleting that folder and file in your FATAL_ERROR message.
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "Out of source builds required with CMake. "
"Please clean up the CMakeFiles/ directory and CMakeCache.txt file.")
endif()

Trying to configure CMake tool chain on Ubuntu

The software will eventually run on an embedded Linux platform. To start, we wrote a library, with all C files in the same folder, and C++ files in a test folder under it.
MyLib
a.c
b.c
MyLib/test
test.cpp
This works on Windows 10, using CMake, Ninja and CLang plus doctest as a test framework. All of these tools are installed under vcpkg.
I am now trying to get everything configured and running on Ubuntu 16.04. All of the tools and source code have been retrieved from our repository. I have tried to build the library and test with Qt, cmake-gui and the command line without success.
Using CMake-gui, after browsing to the source and destination, clicking the Configure button causes the error
CMake Error: CMake was unable to find a build program corresponding to "Ninja".
CMAKE_MAKE_PROGRAM was not set.
The ninja program is in ~/../vcpkg/downloads/tools/ninja-1.8.2-linux/ folder.
I had different errors when trying to build from the command line.
Are there any examples of configurations that work with controlled tools instead of those in the environment?
Edit: added
CMakeLists.txt
cmake_minimum_required(VERSION 3.14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
project(PSOC_LIB)
option(BUILD_TESTS "bulid tests project" OFF)
set(psoc_lib_VERSION_MAJOR 0)
set(psoc_lib_VERSION_MINOR 1)
set(psoc_lib_VERSION_PATCH 0)
set(psoc_lib_VERSION "${psoc_lib_VERSION_MAJOR}.${psoc_lib_VERSION_MINOR}.${psoc_lib_VERSION_PATCH}")
set(PROJ_NAME "\"PSOC Library\"") # PROJECT_NAME is a predefined variable
set(PROJECT_DESCRIPTION "\"Crossplatform library for products\"")
configure_file(include/psoc/config.h.in
${CMAKE_BINARY_DIR}/include/psoc/config.h
)
set(SOURCES
# 5 *.c files
)
add_library(PSOC_LIB ${SOURCES})
target_include_directories(PSOC_LIB PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(PSOC_LIB PRIVATE _CRT_SECURE_NO_WARNINGS=1)
if (BUILD_TESTS)
include(CTest)
enable_testing()
add_subdirectory(test)
endif (BUILD_TESTS)
test/CmakeLists.txt
cmake_minimum_required(VERSION 3.10)
set(TEST_SOURCES
test.cpp
)
find_package(doctest CONFIG REQUIRED)
add_executable(test_runner test_runner.cpp ${TEST_SOURCES})
target_compile_definitions(test_runner PRIVATE _SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING) #silence warnings about allocator<void> deprecation
target_compile_definitions(test_runner PRIVATE _WIN32_WINNT=0x0601) #target windows 7
target_link_libraries(test_runner PSOC_LIB doctest::doctest)
add_test(all_tests test_runner)
Under Windows, the files in the test folder are build even when BUILD_TESTS is OFF. Under Linux, the test and Testing folders are created only when BUILD_TESTS is ON.
I created a shell script that builds an executable test file.
#!/bin/bash
# Build a debug version of the PSOC_LIB and related tests
mkdir build
cd build
../../../vcpkg_pml/vcpkg/downloads/tools/cmake-3.14.0-linux/cmake-3.14.0-Linux-x86_64/bin/cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -S ../
ninja

Error with variables when invoking CMake from CMake

I need to invoke cmake from within cmake so that I can have binaries built before project files are generated. I have the following CmakeLists.txt:
cmake_minimum_required(VERSION 3.2)
project(StarEngine)
set(CMAKE_CXX_FLAGS "-std=c++11")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
find_package(OpenGL REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})
#copy the other cmake file into where we'd like to invoke cmake
configure_file(deps-CMakeLists.txt deps/CMakeLists.txt)
execute_process(COMMAND ${CMAKE_COMMAND} . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
#eventually binaries will be built, for now this doesn't accomplish anything
execute_process(COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/deps)
And its friend, deps-CmakeLists.txt, a test script:
set(GENERATED_DIR "test")
MESSAGE( STATUS ${GENERATED_DIR} )
In the following file structure:
Project
build
Code
CmakeLists.txt
deps-CmakeLists.txt
No matter what I put in for the variable value, it is blank when displayed in MESSAGE. I imagine this is weird behavior resulting from invoking cmake from cmake. I had a bunch of other strange errors to, but I suspect if I can figure out this one that will help crack them all.
Thanks to #Florian, the problem was with variable replacement and I needed to add the COPYONLY option to configure_file

How to instruct CMake to use the build architecture compiler

When using CMake for cross compiling, one generally specifies a toolchain file via the CMAKE_TOOLCHAIN_FILE option. In GNU terminology, one can specify the host architecture toolset using this file. However, one can generally not expect to be able to execute anything built with this toolchain. So often enough, some build tools need to be compiled for the build architecture.
Consider the following setup. I have two source files genfoo.c and bar.c. During build, genfoo.c needs to be compiled and run. Its output needs to be written to foo.h. Then I can compile bar.c, which #include "foo.h". Since CMake defaults to using the host architecture toolchain, the instructions for bar.c are easy. But how do I tell it to use the build architecture toolchain for compiling genfoo.c? Simply saying add_executable(genfoo genfoo.c) will result in using the wrong compiler.
CMake can only handle one compiler at a time. So - if you don't go the long way to set up the other compiler as a new language - you will end up with two configuration cycles.
I see the following approaches to automate this process:
Taking the example "CMake Cross Compiling - Using executables in the build created during the build?" from the CMake pages as a starting point I'll get:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# When crosscompiling import the executable targets
if (CMAKE_CROSSCOMPILING)
set(IMPORT_PATH "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Point it to the export file path from a native build")
file(TO_CMAKE_PATH "${IMPORT_PATH}" IMPORT_PATH_CMAKE)
include(${IMPORT_PATH_CMAKE}/genfooTargets.cmake)
# Then use the target name as COMMAND, CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Only build the generator if not crosscompiling
if (NOT CMAKE_CROSSCOMPILING)
add_executable(genfoo genfoo.cpp)
export(TARGETS genfoo FILE "${CMAKE_CURRENT_BINARY_DIR}/genfooTargets.cmake")
endif()
Then using a script like:
build.sh
#!/bin/bash
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ..
fi
cmake --build hostBuild
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DIMPORT_PATH=${PWD}/hostBuild -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
cmake --build crossBuild
I'll get the desired results by calling ./build.sh.
Splitting the CMakeLists.txt and maybe even replace the export()/include() with something where I know the output path of my build tools e.g. by using CMAKE_RUNTIME_OUTPUT_DIRECTORY would simplify things:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(FooBarTest)
# Then use the target name as COMMAND. CMake >= 2.6 knows how to handle this
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/foo.h
COMMAND genfoo
)
add_executable(bar bar.cpp ${CMAKE_CURRENT_BINARY_DIR}/foo.h)
target_include_directories(bar PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
buildTools/CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(BuildTools)
add_executable(genfoo genfoo.cpp)
build.sh
#!/bin/bash
if [ ! -d crossBuild ]; then
cmake -E make_directory crossBuild
cmake -E chdir crossBuild cmake .. -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake
fi
if [ ! -d hostBuild ]; then
cmake -E make_directory hostBuild
cmake -E chdir hostBuild cmake ../buildTools -DCMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${PWD}/crossBuild
fi
cmake --build hostBuild
cmake --build crossBuild
References
Making a CMake library accessible by other CMake packages automatically
CMake build multiple targets in different build directories
How do I make CMake output into a 'bin' dir?
It is possible to do that completely within CMake.
The trick is to run a separate CMake configuring stage within its own space, silently dismissing every crosscompiling setting and using the host's default toolchain, then import the generated outputs into it's parent, crosscompiling build.
First part:
set(host_tools_list wxrc generate_foo)
if(CMAKE_CROSSCOMPILING)
# Pawn off the creation of the host utilities into its own dedicated space
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools)
file(TO_NATIVE_PATH ${CMAKE_COMMAND} native_cmake_command)
file(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} native_cmake_current_source_dir)
execute_process(
COMMAND "${native_cmake_command}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "${native_cmake_current_source_dir}"
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
add_custom_target(host_tools
COMMAND ${CMAKE_COMMAND} --build . --target host_tools --config $<CONFIG>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/host_tools
)
include(${CMAKE_CURRENT_BINARY_DIR}/host_tools/host_tools.cmake)
foreach(tgt IN ITEMS ${host_tools_list})
add_dependencies(host${tgt} host_tools)
endforeach()
else()
# Add an empty target, host tools are built inplace
add_custom_target(host_tools
DEPENDS ${host_tools_list}
)
endif()
... then you add the usual add_executable and whatever ...
At the end:
if(NOT CMAKE_CROSSCOMPILING)
foreach(tgt IN ITEMS ${host_tools_list})
add_executable(host${tgt} ALIAS ${tgt})
endforeach()
export(TARGETS ${host_tools_list} NAMESPACE host FILE host_tools.cmake)
endif()
When it crosscompiles, it pawns off the creation of the host-run tools into its own dedicated space, and imports the targets as "hostwxrc" and "hostgenerate_foo", with a dependency on generating the host_tools themselves .
When it doesn't crosscompile, it builds wxrc and generate_foo as-is, and aliases them to hostwxrc and hostgenerate_foo.
After this, when you use $<TARGET_FILE:wxrc>, you refer to the wxrc built for the target platform, and $<TARGET_FILE:hostwxrc> refers to the wxrc built for the host platform, regardless whether they are the same or not.

What is INSTALL_DIR useful for in ExternalProject_Add command?

I don't understand the usage of INSTALL_DIR in ExternalProject_Add command. I try to use it but it does not seem to work. Here is an example of a CMakeLists.txt, using Eigen library which compiles quickly:
cmake_minimum_required (VERSION 2.6)
project (example CXX)
include(ExternalProject)
include(ProcessorCount)
set(CMAKE_VERBOSE_MAKEFILE ON)
ProcessorCount(N)
if(NOT N EQUAL 0)
set(CMAKE_BUILD_FLAGS -j${N})
endif()
ExternalProject_Add
(
mylib
PREFIX myprefix
DOWNLOAD_COMMAND wget http://bitbucket.org/eigen/eigen/get/3.2.4.tar.gz && tar xvzf 3.2.4.tar.gz -C mylib --strip-components=1
)
I chose the following project hierarchy:
project
CMakeLists.txt
build/
From build repository, I type:
cmake ..
make
The installation process fails with the following message:
file cannot create directory: /usr/local/include/eigen3.
Maybe need administrative privileges.
As far as I understand, it means that I need to define a "prefix" during the configuration step:
cmake -D CMAKE_INSTALL_PREFIX=$INSTALL_DIR ..
But, the INSTALL_DIR variable is already defined in the ExternalProject_Add command. However, I get the same error when I modify the value of INSTALL_DIR by adding
INSTALL_DIR myprefix/src/install
in the ExternalProject_Add command.
So, what is INSTALL_DIR useful for?
What am I doing wrong?
Of course, I know how to provide my own configuration command to add a prefix and solve the problem. But it is not my question. My question is: if I have to do that, what is the purpose of INSTALL_DIR?
From what I found in this discussion https://www.mail-archive.com/cmake#cmake.org/msg51663.html (scroll to the end of the page to navigate through the thread messages) it is indeed pretty common thing to use CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/contrib
Furthermore, lurking through the ExternalProject.cmake module I found out that the only effect setting this directory has is that CMake will create directory specified in INSTALL_DIR before doing anything else.
Also, it will set the property that you can gather through ExternalProject_Get_Property(${project_name} install_dir) command.
And that's pretty much it.
// As of CMake version 3.2.2