cmake add_custom_command pre_build - c++

I am writing cmake example for the first time.
Here is a part of CMakeFiles.txt:
add_custom_command(
OUTPUT ${CODEGEN_SRC}
PRE_BUILD
COMMAND ${CODEGEN_CMD} ${SERVICE_XML} --generate-cpp- code=/home/hello/include/gen/testGenCode
COMMENT "Generate gdbus code"
)
add_custom_target(${CODEGEN_TARGET}
DEPENDS ${CODEGEN_SRC}
)
Generate code using gdbus-codegen-glibmm in command syntax using add_custom_command.
However, contrary to my expectations, when I actually do cmake and make, it looks like this:
cmake ..
CMake Error at Server/CMakeLists.txt:1 (ADD_EXECUTABLE):
Cannot find source file:
#### generate File ####
CMake Error at Client/CMakeLists.txt:36 (ADD_EXECUTABLE):
Cannot find source file:
#### generate File ####
Then, if you proceed with make, the contents of COMMANT in add_custom_command are output, and codes are actually generated.
After checking the generated code, proceed with cmake .. and make again to build normally.
Server/CMakeLists.txt, Client/CMakeLists.txt
I set the dependency of ${CODEGEN_TARGET} using ADD_DEPENDENCIES in , but it works differently than I expected.
How can I get the gdbus-codegen-glibmm command to run first?

add_custom_command will run the command during build phase (when running make). Since it generate the files required by the next target, it will fail if the file have never been generated.
You can configure the file when running cmake too, using execute_process() in addition of add_custom_command(). You can also use configure_file() to create a placeholder for the target before you erase it later with gdbus-codegen-glibmm when running make.

Related

Can someone expand what is meant by 'configure' and 'build' with CMake files

I am downloading this code from GitHub (subdivision-regression), and am getting stuck following the instructions:
To build doosabin_regression:
Run CMake with an out of source build.
Set COMMON_CPP_INCLUDE_DIR to the full path to rstebbing/common/cpp.
Set DOOSABIN_INCLUDE_DIR to the full path to rstebbing/subdivision/cpp/doosabin/include.
Set Ceres_DIR to the directory containing CeresConfig.cmake.
Set GFLAGS_INCLUDE_DIR, GFLAGS_LIBRARY and RAPID_JSON_INCLUDE_DIR. (Add -std=c++11 to CMAKE_CXX_FLAGS if compiling with gcc.)
Configure.
Build.
I have edited the CMakeLists.txt file to put the correct paths in. I then created a new directory called subdivision-regression-bin and ran:
cmake ../subdivision-regression/src
It completes this and displays:
-- Configuring done
-- Generating done
-- Build files have been written to: /home/hert5584/RStebbing/subdivision-regression-bin
However, when I try and run the example code, it cannot find the files listed in CMakeLists.txt (I know they are the right paths as otherwise CMake does not run).
I have tried running:
sudo make install
But get the following error:
make: *** No rule to make target 'install'. Stop.
Any ideas why this isn't working? Have the above steps Configured and Built the files?
The ordered CMake idiom to understand is:
The Configure step
The Generate step (This is often subsumed in the Configure step, and not mentioned explicitly, as in this case.)
The Build step (in which you actually compile/link your code into libraries/executables)
Take a look at this resource for information about the configure and generate stages.
You didn't appear to perform the steps to set CMake cache variables. For these you have to use CMake command line options (-D specifically). So run CMake as something like this instead to set all six variables:
cmake -DCOMMON_CPP_INCLUDE_DIR=/rstebbing/common/cp -DDOOSABIN_INCLUDE_DIR=...[More CMake Cache variables]... ../subdivision-regression/src
For building, try just running make without sudo or install:
make

How to trigger CMake reconfiguration from a target?

I have the following setup:
- build/
- conanbuildinfo.cmake (generated)
- conanfile.py
- CMakeLists.txt
A conan command is ran before CMake, generating conanbuildinfo.cmake. This contains include paths etc. to be used during the compilation later. If I change the conanfile, I want to trigger conan again and a re-run of CMake from the generated ninja build. I have a script that can call conan and it updates everything properly. However, this happens after CMake was ran and even though conanbuildinfo was changed, CMake won't run once more. This causes ninja to "not see" the changes in the dependency graph, so it doesn't rebuild everything it has to rebuild. That means I have to run ninja twice to get everything to update. The way I trigger the reconfigure currently is like this:
set(DS_CONFIG_INDICATOR ${CMAKE_BINARY_DIR}/ds_configured)
add_custom_command(
DEPENDS ${PROJECT_SOURCE_DIR}/conanfile.py
OUTPUT ${DS_CONFIG_INDICATOR}
COMMAND ${CMAKE_COMMAND} -E env --unset=PYTHONPATH ${PYTHON_BINARY} ${PROJECT_SOURCE_DIR}/scripts/common/reconfigure.py ${DS_CONFIG_INDICATOR} ${PROJECT_SOURCE_DIR}
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Checking if reconfigure is needed"
USES_TERMINAL
)
add_custom_target(ConanReconfigure
DEPENDS ${DS_CONFIG_INDICATOR}
)
Is there a way to trigger a reconfigure after this script was ran?
I tried using the following without any success:
CMAKE_CONFIGURE_DEPENDS
Running cmake from the reconfigure.py script
Touching the main CMakeLists.txt from the reconfigure.py script
Using execute_process to run the script
Why didn't execute_process work?
It seems to me like this should work if you use execute_process (not add_custom_command) to run conan/reconfigure.py before any of the CMake logic that depends on its output, combined with adding the input files of that command to CMAKE_CONFIGURE_DEPENDS.
Trying to run something before CMake won't work... but you don't need to do that, anyway. I think your problem is that you are trying to solve the wrong question. Instead, look at it as a) you want to run something during CMake's execution, and b) you want to re-run CMake if your "conanfile" changes. Re-running CMake will re-run conan.

cmake error "CMake Error: The source directory ".../p4c/build/[-DCMAKE_BUILD_TYPE=RELEASE" does not exist

I'm getting the cmake error when installing p4c. Below is the cmake command to be run
cmake .. [-DCMAKE_BUILD_TYPE=RELEASE|DEBUG] [-DCMAKE_INSTALL_PREFIX=<path>] [-DENABLE_DOCS=ON (default off)] [-DENABLE_P4RUNTIME_TO_PD=OFF (default on)]
I'm getting the below error
CMake Error: The source directory "/home/users/phani/p4c/build/[-DCMAKE_BUILD_TYPE=RELEASE" does not exist.
Specify --help for usage, or press the help button on the CMake GUI.
DEBUG]: command not found
source files, CmakeLists.txt are in path "/home/users/phani/p4c", build is done is seperate subdirectory as shown in the link. Please help me to resolve the error
The syntax:
cmake .. [-DCMAKE_BUILD_TYPE=RELEASE|DEBUG] [-DCMAKE_INSTALL_PREFIX=<path>] [-DENABLE_DOCS=ON (default off)] [-DENABLE_P4RUNTIME_TO_PD=OFF (default on)]
is commonly used to quickly describe what options can be added or not to a command line.
To perform a simple build, do
cmake ..
If you want to specify the build type, you do:
cmake .. -DCMAKE_BUILD_TYPE=RELEASE
or
cmake .. -DCMAKE_BUILD_TYPE=DEBUG
etc.
In other words, when you see
command [option] [option=val1|val2]
arguments under [] are optional, and char | means "or". You should not write these characters in the real command line you type in your terminal

Running Google test at build time with CMake generated system

My configuration has CMake 3.6, Visual Studio 2015 and latest Google test from GitHub. I add my unit tests through one of my cmake functions addGtest and do the build. After this I can run the test from my RUN_TESTS target or using ctrl + F5 in VS and works as expected.
The final goal is to run the unit tests at build time using the CMake dependency management. For now, as a first step, I have enhanced my function to create a custom_target (included the entire function, in case there are unforeseen issues in the working part), but not build it:
function (addGtest)
# vvvv this part works as explained vvvv #
set (optBOOLS)
set (optSINGLES EXE)
set (optLISTS DLL_LIST)
cmake_parse_arguments (myARGS
"${optBOOLS}" "${optSINGLES}" "${optLISTS}" ${ARGN})
# addExecutable is a function that adds target executables
set(myARGS_DLL_LIST gtest_main gtest "${myARGS_DLL_LIST}")
addExecutable (EXE ${myARGS_EXE} DLL_LIST ${myARGS_DLL_LIST} ${myARGS_UNPARSED_ARGUMENTS})
add_test (NAME ${myARGS_EXE} COMMAND ${myARGS_EXE} WORKING_DIRECTORY
${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
) # so it can be run using ctest
# ^^^^ this part works as explained ^^^^ #
add_custom_target (${myARGS_EXE}.tgt DEPENDS ${myARGS_EXE}
COMMAND ${myARGS_EXE} --gtest_output="xml:${myARGS_EXE}.xml"
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/$<$<CONFIG:Release>:Release>$<$<CONFIG:Debug>:Debug>/bin
)
endfunction (addGtest)
As expected when I perform the build, a new target, say, utMyTest.tgt is added to VS, but it is not built. Now when I build this new target by hand in VS, I expect that the test will be run. But it doesn't and gives the following error:
1> The filename, directory name, or volume label syntax is incorrect.
I tried providing full path to the COMMAND option, removing double quotes around --gtest_output value, but to no avail. On the other hand when I cd to the working directory in a command line window and invoke the exe, it works fine!!
The first question is how do I fix it to run the test by building this new target? After that, I plan to add_custom_target (${myARGS_EXE}.run) and add_dependencies (${myARGS_EXE}.run ${myARGS_EXE}.tgt). Would this then run the test whenever the exe changes? Or should I do something else? Thank you for your help.
Could not add so much details in the comment, hence this answer.
1. Answer to the original problem
Since I needed the configuration dependent path in the WORKING_DIRECTORY option of the add_custom_target command, but cannot pass generator expressions to it, the idea is to use the CMAKE_CFG_INTDIR variable so:
add_custom_target (${myARGS_EXE}.tgt
DEPENDS ${myARGS_EXE}
COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
WORKING_DIRECTORY ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin
)
Now, when you build the above target, the unit test is run in the WORKING_DIRECTORY which is not entirely desirable, since that is the install directory for libs and exes. It would be really nice to ...
2. Run the unit test from its build directory
While, at the same time, picking up the DLL paths from within Visual Studio, and storing the Gtest generated .xml file in the build directory. This is the solution:
In CMake version 3.10 CMAKE_MSVCIDE_RUN_PATH property was added. In the project wide CMakeLists.txt, set(CMAKE_MSVCIDE_RUN_PATH ${CMAKE_INSTALL_PREFIX}/${CMAKE_CFG_INTDIR}/bin) - thanks to this solution #3, we can appendPATH to point to our install directory. And then replace the above add_custom_target command with this:
add_custom_command (
TARGET ${myARGS_EXE} POST_BUILD
COMMAND ${myARGS_EXE} --gtest_output=xml:${myARGS_EXE}.xml
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}
)
This solution avoids the mess of creating additional targets. Clearly only when myARGS_EXE is built, the unit test is run. Obviously myARGS_EXE's transitive dependency on other DLLs is covered also.
If you have other elegant solutions, please post.

cmake: trying to call msbuild during cmake script execution

I'm trying to migrate my Visual Studio solution to CMake.
I have two projects - generator (generator.exe generates C++ sources from text files) and myProj (includes some text files that have to be processed by generator.exe).
What I want is:
build generator project
use generator.exe from step1 to generate C++ source files from text files in project myProj
put those generated source files in resulting VS project for myProj
what I've so far:
###################################################################
# in root/generator/CMakeLists.txt:
set(SRC_LIST .... )
set(HDR_LIST .... )
add_executable(generator ${SRC_LIST} ${HDR_LIST})
###################################################################
# in root/my_proj/CMakeLists.txt:
add_subdirectory(../generator/ ../generator/cmake_out)
# TRY TO BUILD GENERATOR.EXE. DON'T WORK, BECAUSE ../generator/cmake_out/ IS EMPTY YET
execute_process(COMMAND msbuild ../generator/cmake_out/generator.vcxproj)
# <copy generated files to ./src>
add_subdirectory(src)
###################################################################
# in root/my_proj/src/CMakeLists.txt:
set(SRC_LIST SomeSource.cpp .... )
set(HDR_LIST SomeSource.h .... )
add_library(myProj STATIC ${SRC_LIST} ${HDR_LIST} )
So, what is wrong here? Why execute_process() fails? Seems like CMake's order of execution is absolutely chaotic.
Use ADD_CUSTOM_COMMAND to execute generator.exe during compilation. Be sure to specify all of the OUTPUT files generated. List those output files as sources for myProj. CMake should build you a solution with two projects that will build generator first, execute it to generate the automatic myProj files, then build myProj.
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/output1.cpp ${CMAKE_CURRENT_BINARY_DIR}/output1.h
COMMAND generator
DEPENDS generator
)
add_library(myProj ${CMAKE_CURRONT_BINARY_DIR}/output.h ${CMAKE_CURRENT_BINARY_DIR}/output.cpp)
It looks like execute_process failing is the least of your problems, but to answer your question: First of all you can see the result of the called command using
execute_process(COMMAND msbuild ../generator/cmake_out/generator.vcxproj
RESULT_VARIABLE result)
message(STATUS "Result: ${result}")
You will probably see "The system cannot find the file specified" because the CMake shell does not know what directory the msbuild command is in. You can just give the full path to msbuild, for example on my system (VS 2013), I would use:
execute_process(COMMAND "C:\\Program Files\\MSBuild\\14.0\\Bin\\MSBuild.exe"
../generator/cmake_out/generator.vcxproj)