CPack create packages with executables from different source tree - cmake

The problem is as follows:
Project structure:
ProjectDir
- CMakeLists.txt
- src
-- CMakeLists.txt
-- FirstApp
--- CMakeLists.txt
--- ... sources ...
-- SecondApp
--- CMakeLists.txt
--- ... sources ...
- tools
-- CMakeLists.txt
-- SomeTool
--- CMakeLists.txt
--- ... sources ...
-- SomeOtherTool
--- CMakeLists.txt
--- ... sources ...
What I want to achieve is:
package (let it be rpm or deb) with SomeTool binaries;
package with FirstApp, SecondApp AND SomeOtherTool binaries;
As far as I know:
CPack is putting into packages content the stuff that is defined in install command;
CPack cannot be called ( include(CPack) ) twice in the same tree (for example it cannot be called in CMakeLists.txt at src level AND SecondApp level);
What do I have
In ProjectDir/tools/SomeTool/CMakeLists.txt I've (it's pseado code):
PROJECT( SomeTool )
SET(TARGET SomeTool)
SET(CPACK_GENERATOR "RPM")
SET(CPACK_PACKAGE_NAME "SomeTool")
# ...
# all the other CPACK_* stuff
# ...
include(CPack)
add_custom_target(${TARGET}-package
COMMAND cpack --config "${CMAKE_CURRENT_BINARY_DIR}/CPack${PROJECT_NAME}Config.cmake")
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
This way I can call make SomeTool-package and it'll create package (SomeTool.rpm) with content /usr/bin/SomeTool. Great!
I can have very similar CMakeLists.txt in ProjectDir/src/ dir:
# src/CMakeLists.txt
PROJECT( MainProject )
SET(CPACK_GENERATOR "RPM")
SET(CPACK_PACKAGE_NAME "MainProject")
# ...
# all the other CPACK_* stuff
# ...
include(CPack)
add_custom_target(MainProject-package
COMMAND cpack --config "${CMAKE_CURRENT_BINARY_DIR}/CPack${PROJECT_NAME}Config.cmake")
add_subdirectory(FirstApp)
add_subdirectory(SecondApp)
# src/FirstApp/CMakeLists.txt
SET(TARGET FirstApp)
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
# src/SecondApp/CMakeLists.txt
SET(TARGET SecondApp)
SET(SOURCES ...)
SET(HEADERS ...)
add_executable(${TARGET} ${SOURCES} ${HEADERS})
install(TARGETS ${TARGET}
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin)
This way I can call make MainProject-package and it'll create package (MainProject.rpm) with content /usr/bin/FirstApp and /usr/bin/SecondApp. Great!
SomeOtherTool also have a CMakeLists.txt which looks the same as FirstApp and SecondApp CMakeLists.txt and I can call make SomeOtherTool and it'll produce SomeOtherTool binaries.
The Question
As CPack is puting into packages stuff connected to install command, how can I connect SomeOtherTool with my MainProject-package ?
My solution would (is) be to put another install clause at the end of src/CMakeLists.txt that'd look like:
add_dependency(MainProject SomeOtherTool)
install(FILES ${CMAKE_BINARY_DIR}/SomeOtherTool DESTINATION ${CMAKE_INSTALL_PREFIX}/usr/bin )
Is there any other way? This solution doesn't look clean.. If I change the SomeOtherTool executable name I'll have to change it in here also. The same goes with install path.

Related

how to split 'header', 'src', 'test' dir in cmake?(and donot add cmakelist.txt in each dir)

when building a project stucture like following:
LinearAlgebra
|---HEADER
|-----|---Linear.h
|---SRC
|-----|---Linear.cpp
|---TEST
|-----|---hello_test.cc
here is my CMakeList.txt:
cmake_minimum_required(VERSION 3.10)
project(LinearAlgebra )
set(CMAKE_CXX_STANDARD 11)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
add_library(LA_HEADER INTERFACE header/Linear.h)
add_library(LA_SRC INTERFACE src/Linear.cpp)
target_include_directories(LA_HEADER INTERFACE "${PROJECT_SOURCE_DIR}/header" "${PROJECT_SOURCE_DIR}/src")
enable_testing()
add_executable(
hello_test
test/hello_test.cc
)
target_link_libraries(
hello_test
gtest_main
LA_HEADER
LA_SRC
)
include(GoogleTest)
gtest_discover_tests(hello_test)
it works fine with cmake -S . -B build, but when it comes to cmake --build build following error occured:
Undefined symbols for architecture x86_64:
"Linear::Linear()", referenced from:
HelloTest_BasicAssertions_Test::TestBody() in hello_test.cc.o
it seems something wrong with my cmake file that didn't tell Linear.h where Linear.cpp located. So how to fix it ?? thanks for your help...
seems i misunderstand add_library, change three lines and it works out:
cmake_minimum_required(VERSION 3.10)
project(LinearAlgebra )
include_directories(header) # include_directories instead of add_library for .h files
add_library(LA_LIB src/Linear.cpp) # use add_library for .cpp files only!!!
set(CMAKE_CXX_STANDARD 11)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
enable_testing()
add_executable(
hello_test
test/hello_test.cc
)
target_link_libraries(
hello_test
gtest_main
LA_LIB # link LA_LIB only..
)
include(GoogleTest)
gtest_discover_tests(hello_test)
leave it here for anyone have the same requirements.

How to add include directories from ExternalProject_Add into project?

I have tried following this solution this individual has from this question. I am trying to do this with boost with the following cmake file in a separate directory from my Source:
#---------------------------------------------------------------------------
# Get and build boost
SET_PROPERTY(DIRECTORY PROPERTY "EP_BASE" ${ep_base})
SET(boost_GIT_TAG "origin/master")
set( Boost_Bootstrap_Command )
if( UNIX )
set( Boost_Bootstrap_Command ./bootstrap.sh )
set( Boost_b2_Command ./b2 )
else()
if( WIN32 )
set( Boost_Bootstrap_Command bootstrap.bat )
set( Boost_b2_Command b2.exe )
endif()
endif()
ExternalProject_Add(Boost_external_Download
GIT_REPOSITORY "https://github.com/boostorg/boost.git"
GIT_TAG ${boost_GIT_TAG}
BUILD_IN_SOURCE 1
UPDATE_COMMAND ""
PATCH_COMMAND ""
CONFIGURE_COMMAND ${Boost_Bootstrap_Command}
BUILD_COMMAND ${Boost_b2_Command} install
--without-python
--without-mpi
--disable-icu
--prefix=${CMAKE_BINARY_DIR}/Boost
--threading=single,multi
--link=shared
--variant=release
-j8
INSTALL_COMMAND ""
INSTALL_DIR ""
)
if( NOT WIN32 )
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
else()
set(Boost_LIBRARY_DIR ${CMAKE_BINARY_DIR}/Boost/lib/ )
set(Boost_INCLUDE_DIR ${CMAKE_BINARY_DIR}/Boost/include/boost/ )
endif()
ExternalProject_Get_Property(Boost_external_Download BINARY_DIR)
SET(Boost_DIR ${BINARY_DIR} CACHE PATH "")
add_library(Boost_external SHARED IMPORTED)
The only thing that is different between one of the solutions and mine is that I don't have the set_target_properties right after I add the library. Since boost has a lot of libraries in there and I am not exactly sure what needs to be added.
In my Source Folder, my CMakeLists.txt does the following:
include_directories(${Boost_INCLUDE_DIR})
add_executable(Main main.cpp)
target_link_libraries(Main Boost_external)
add_dependencies(Main Boost_external_Download)
However, in main.cpp when I use #include <boost/process.hpp> just to see if it links, I get the error that #include <boost/process.hpp> no such file or directory. When I try to make the project. I am not really sure where I am going wrong with this so any helpful advice would be appreciated.
Edit: structure
Root Folder
|
- CmakeLists.txt
- Externals Directory
|
| - Externals.cmake
| - boostExternal.cmake
| - other external cmake files
- Source Directory
|
| - CmakeLists.txt
| - main.cpp
The Root Cmake calls the Externals.cmake file. Which then includes all the other Cmake files within that directory. Once those are finished, the root Cmake file add the directory Source, and that Cmake file has the call to include_directories(${Boost_INCLUDE_DIR}).

*.pb.h and *.pb.cc protobuf files not getting generated

I am using protobuf_generate_cpp() in order to generate *.cc and *.h files from the *.proto file but it is not getting executed. I do not get any error message, the lines are just skipped. The CMakeLists.txt file looks something like this:
cmake_minimum_required(VERSION 3.1.2)
cmake_policy(SET CMP0028 NEW)
project(ProjectName CXX C)
execute_process(COMMAND conan install . WORKING_DIRECTORY ${CMAKE_HOME_DIRECTORY})
include(conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
find_package(Protobuf REQUIRED)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS /path/to/NAME.proto)
add_custom_command(
OUTPUT NAME.pbs.h
OUTPUT NAME.pbs.cc
DEPENDS NAME.proto
COMMAND protoc --cpp_out=$(CMAKE_BINARY_SOURCE_DIR) --proto_path=../path/to/NAME.proto
)
set(ProjectName-HeaderFiles
${ProjectName-HeaderFiles}
<list of all header files>
)
set(ProjectName-SourceFiles
${ProjectName-SourceFiles}
<list of all source files>
)
add_executable(ProjectName ${PROTO_SRCS} ${PROTO_HDRS}
<list of all other executables>
)
add_definitions(
-D_CONSOLE
-DWIN32
-D_DEBUG
-DSTANDALONE_PROGRAM
)
include_directories(
<list of all include paths>
)
target_link_libraries( ProjectName
PUBLIC
CONAN_PKG::Protobuf
LIB1
LIB2
)
My solution is created #location CMAKE_BINARY_SOURCE_DIR but NAME.pb.h and NAME.pb.cc files do not get created. Could someone let me know what the issue might be? Any suggestions are appreciated.

Adding google-test to a subfolder in a CMake project

I have just added google-test source code to libs/gtest-1.6.4 directory in my project. There is a libs/gtest-1.6.4/CMakeLists.txt file. In the top-most CMakeLists.txt, I have added add_subdirectory('libs/gtest-1.6.4'). The structure of the project is
|- CMakeLists.txt
|- src
|- CMakeLists.txt
|- *.h and *.cc
|- libs
|- gtest-1.6.4
|- CMakeLists.txt
|- gtest source code etc.
|- other subdirectories
Now I add #include "gtest/gtest.h" in one of the header file. Compilation fails with
gtest/gtest.h: No such file or directory
compilation terminated.
Here is the snippet of my src/CMakeLists.txt file.
set( Boost_USE_STATIC_LIBS ON )
find_package( Boost COMPONENTS graph regex system filesystem thread REQUIRED)
.. Normal cmake stuff ...
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS} )
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
add_executable(Partitioner
print_function.cc
methods.cc
partitioner.cc
main.cc
)
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
What am I missing?
Looking at GTest's CMakeLists.txt, it looks like their include path is ${gtest_SOURCE_DIR}/include. They also define the library as a CMake target called gtest (this is wrapped in a macro cxx_library(gtest ...) currently on line 70).
So it looks like you need to do:
...
# This line is added for google-test
INCLUDE_DIRECTORIES(${GTEST_INCLUDE_DIRS} ${COMMON_INCLUDES})
INCLUDE_DIRECTORIES(${gtest_SOURCE_DIR}/include ${COMMON_INCLUDES})
...
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${GTEST_LIBRARIES})
TARGET_LINK_LIBRARIES(Partitioner ${Boost_LIBRARIES} gtest)
You'd also have to ensure that in your root CMakeLists.txt, you've called add_subdirectory(libs/gtest-1.6.4) before add_subdirectory(src) so that the GTest variables are correctly set when they're being used in "src/CMakeLists.txt".
As mentioned in accepted answer,
I did put my GoogleTest stuff up before my add_subdirectory() lines and it worked.
# The ROOT CMakeLists.txt
enable_testing()
include(CTest)
# https://google.github.io/googletest/quickstart-cmake.html
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/....zip
)
# For Windows: Prevent overriding the parent project's compiler/linker settings
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(googletest)
include(GoogleTest)
add_subdirectory(some)
add_subdirectory(other)
add_subdirectory(another)
And in one of those sub directory, I see tests work.
# A CMakeLists.txt in a sub directory
#enable_testing() # NOT REQUIRED, hence, commented out
#include(CTest) # NOT REQUIRED, hence, commented out
#include(GoogleTest) # NOT REQUIRED, hence, commented out
add_executable(
mytest
test/mytest.cpp
)
target_link_libraries(
mytest
gtest_main
)
gtest_discover_tests(
mytest
)

Compile sources in `src` directory to binaries in `bin` directory with CMake

My project directory contains a CMakeLists.txt file and src and include directories at its root. src also contains its own CMakeLists.txt, which is linked by the one at the root. Is there a way I can specify to CMake to set a default global build directory so that the syntax in src/CMakeLists.txt is close to the following?
include_directories(include)
add_executable(first main.cpp foo.cpp)
add_executable(second bar.cpp)
I would like this directory tree to be built:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
foo.cpp
bar.cpp
include/
...
bin/ (or build/)
first
second
You could set CMAKE_RUNTIME_OUTPUT_DIRECTORY:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
However, this won't create subdirectories inside bin/ for each different target.
If you want that, you could create a helper function to wrap add_subdirectories:
function(my_add_executable TargetName)
set(Files ${ARGV})
list(REMOVE_AT Files 0)
add_executable(${TargetName} ${Files})
set_target_properties(${TargetName} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY
"${CMAKE_SOURCE_DIR}/bin/${TargetName}")
endfunction()
then simply change your calls to:
my_add_executable(first main.cpp foo.cpp)
my_add_executable(second bar.cpp)
For further details, run
cmake --help-variable "CMAKE_RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY"
cmake --help-property "RUNTIME_OUTPUT_DIRECTORY_<CONFIG>"