cmake install does not trigger custom command - c++

In my project I use add_custom_command to generate some output file:
add_custom_command(
OUTPUT ${LIB_NAME}
# commands
)
add_custom_target(Core-static DEPENDS ${LIB_NAME})
I then have instruction to install the library:
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}"
DESTINATION "${CORE_INSTALL_DIR}/lib/"
)
When I manualy build Core-static target, I can then successfuly run installation. However, running install does not trigger the custom command and the library is not produced resulting in an error. Also, for some reason rebuilding the solution (in Visual Studio) does not trigger Core-static project build.

In CMake, installing triggers only ALL (pseudo-)target.
For make your file installable, you need to force ALL target to build your file. Currently, your custom target Core-static is not buit by default (by ALL target). For fix that, add ALL keyword when create the target:
add_custom_target(Core-static ALL DEPENDS ${LIB_NAME})

Related

CMake run custom command with externalproject's target

I have a subproject in my project for generating code used in the project, however i want to include it using ExternalProject so it can be built and ran regardless of the toolchain i use for the main project.
It mostly works except i can't figure out how to use it in add_custom_command, since i want it to use the target rule specified in the docs:
If COMMAND specifies an executable target name (created by the add_executable() command), it will automatically be replaced by the location of the executable created at build time [...]
Simple example of my project setup that replicates the issue:
https://godbolt.org/z/of8G4c4Gf
Replacing the ExternalProject_Add with a simple add_subdirectory makes it work, but wouldn't do what i want in the case of using a different toolchain.
ExternalProject_Add will add the codegen target. However, CMake has no idea what that target is doing and what output it will provide, as that info is now hidden away in the external CMake run. So the outer CMake run has no idea about the codegen binary produced by that step and where it will be located. You need to provide the full path to the executable to add_custom_command manually.
ExternalProject_Add will build codegen and place the resulting binary in a subdirectory inside your build directory. The exact location is toolchain dependent, so it can be tricky to reconstruct the full target path. The most robust way to solve this is:
Add an install step to the codegen project. This will allow you to portably specify which path the installed binary will end up in relative to the install root directory.
Set the INSTALL_DIR option on ExternalProject_Add to a subdirectory inside your PROJECT_BINARY_DIR.
Hardcode the full path to the installed codegen binary in the custom command of the outer CMake project. To work on multiple platforms, you may need to make use of the CMAKE_EXECUTABLE_SUFFIX variable.

how can i make some install command run before compile process?

I will use install command in my CMakeLists like this:
install(DIRECTORY lib-mmm/src/infra/ DESTINATION /home/nick/infra FILES_MATCHING PATTERN "*.h")
this is command to install some directory to some place.
I want this run before other compile process.
but i found when i define it as install, it will be called only when make install, which is after make process.
how can i make install directory command run before real compile process?
Afaik there is no way to do this by using the same project. The install target depends on the targets being build and any dependency of building on the install target would result in a circular dependency.
There are alternatives though:
Use file(COPY)
Use execute_process to set up, build & install another cmake project during configuration. It can be problematic though to get cmake to use the same options for that build. This could also be refined by getting add_custom_command involved...
In your case though simply adding the correct include directory using target_include_directories will probably work better though.

Depending on the INSTALL target of a CMake External Project

Is there a way to identify dependencies of the installation-step of a target in cmake? Here's my situation:
My goal is to be able to download the source code of this project and build it without first installing the dependencies. In other words, I'd like the dependencies to be recognized and installed prior to trying to build the main target. For example, I'm working on including Leptonica as an external project:
set(leptonica_build "${CMAKE_CURRENT_BINARY_DIR}/leptonica")
ExternalProject_Add(
leptonica
DOWNLOAD_DIR ${download_dir}
BINARY_DIR ${leptonica_build}
GIT_REPOSITORY ${OpenCV_git_repository}
GIT_TAG ${OpenCV_git_tag}
TLS_VERIFY true
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=${DOC_READER_INSTALL_PREFIX}
)
Running the target leptonica correctly builds and installs the library into a temporary directory, making itself available to other targets to consume:
add_dependencies(myProgram leptonica)
find_library(LEPT_LIB lept)
target_link_libraries(myProgram ${LEPT_LIB})
The problem is that, when /tmp is cleared and cmake is first executed with the target of myProgram, liblept.so isn't found because it hasn't yet been installed, and consequently an upstream dependency of myProgram hasn't been met until after make install has been run.
In other words, I'd like the build script to first download and install then dependencies, then try to lookup the location of the libraries needed by downstream build steps. Is this possible to do with cmake or should I be accomplishing this goal some other way?
Build and install leptonica from a separate CMakeLists.txt. Alternatively, you can use the same CMakeLists and selectively enable either the ExternalProject-section or the main section of your CMakeLists with a control variable (-DMYPROJECT_INSTALL_DEPS=1)
You can trigger the configure/build steps of leptonica from shell script, or call cmake from the main CMakeLists with execute_process:
execute_process(
COMMAND ${CMAKE_COMMAND} -H... -B...
COMMAND ${CMAKE_COMMAND} --build ... --target install ...
)
That way the entire configuration/build/install steps will get executed in the configuration step of your main project.

Use CMake to run a C++ program post-build

I have an application that is written in C++ that I use CMake to build and release binaries.
I'd like to have the CMakeLists.txt script compile and run a CPP file that is used to timestamp and encrypt a license file after it has built the binaries for the application. I've seen examples of running the execute_process command such as this:
execute_process(COMMAND "gcc -o foo foo.cpp"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
execute_process(COMMAND "./foo"
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
RESULT_VARIABLE MY_FOO_VAR)
I am using Visual Studio 2010 to do the build on Windows. The problem is that I'm not sure how to get CMake to run a program during VS's build process. I want the last thing in the build operation to be the license file timestamp, but I don't really know enough about VS or CMake to get this set up.
You say you want to run the file after your build. execute_process() runs at CMake-time, not at build time. What you're looking for would be add_custom_command():
add_executable(LicenseStamper stamper.cpp)
add_custom_command(
OUTPUT stamped_file.lic
COMMAND LicenseStamper any other arguments
DEPENDS any/dependency.file
COMMENT "Stamping the license"
VERBATIM
)
add_custom_target(
StampTheLicense ALL
DEPENDS stamped_file.lic
)
The custom command will run the executable (and build it first, if necessary). The custom target will drive the custom command - it depends on the command's output, so when the target is built, it will require its dependency to be built, causing the custom command to run.

How to change the executable output directory for Win32 builds, in CMake?

My problem is as such :
I'm developing a small parser using Visual Studio 2010.
I use CMake as a build configuration tool.
But I find the default executable building behaviour, inconvenient.
What I want is, have my final program be located in :
E:/parsec/bin/<exe-name>.<build-type>.exe
rather than
E:/parsec/bin/<build-type>/<exe-name>.exe
How would you do that using CMake ?
There are several options:
Copy the executable after building
Customizing the output-directory for your executable(s)
Copy the executable after building
After a succesful build you can copy the executable (see Beginners answer), but perhaps it is nicer to use an install target:
Use the install command to specify targets (executables, libraries, headers, etc.) which will be copied to the CMAKE_INSTALL_PREFIX directory. You can specify the CMAKE_INSTALL_PREFIX on the commandline of cmake (or in the cmake GUI).
Customizing the output-directory for your executable(s)
Warning: It is not advised to set absolute paths directly in your cmakelists.txt.
Use set_target_properties to customize the RUNTIME_OUTPUT_DIRECTORY
set_target_properties( yourexe PROPERTIES RUNTIME_OUTPUT_DIRECTORY E:/parsec/bin/ )
As an alternative, modifying the CMAKE_RUNTIME_OUTPUT_DIRECTORY allows you to specify this for all targets in the cmake project. Take care that you modify the CMAKE_LIBRARY_OUTPUT_DIRECTORY as well when you build dlls.
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib )
Additional info: Take a look at these questions:
In CMake, how do I work around the Debug and Release directories Visual Studio 2010 tries to add?
CMake : Changing name of Visual Studio and Xcode exectuables depending on configuration in a project generated by CMake
How to not add Release or Debug to output path?
Most probably you will need to copy your binaries with a separate custom command which would look similar to this one:
add_custom_command(target your_target_name
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${EXAMPLE_BIN_NAME} ${PROJECT_BINARY_DIR}/.
)