Let's take a real example - I have two native android lib modules (CMake). First module name is - libtetdecoder (further here - A) and another one is - libtetplayer(further here - B). So, lib A use opencv and lib B use lib A. Then, opencv is shared lib and it means that in order to make it work in lib A I need to include headers as well as .so files.
I do it in CMakeList.txt this way
...
include_directories(${pathToOpenCv}/sdk/native/jni/include)
add_library(lib_opencv SHARED IMPORTED)
set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION
${pathToOpenCv}/sdk/native/libs/${CMAKE_ANDROID_ARCH_ABI}/libopencv_java3.so)
...
As I told above lib B use lib A (but not opencv), so chain looks like this B -> A -> opencv(shared). Question is - if I need in this case include opencv configuration(CMake) in lib B? Because as far as I understood if lib B is going to use lib A, so it means that lib B should implement all the dependencies the same as lib A.
Why I ask, because today I have this implementation in lib A and B, if I try to clean up lib B CMakeList.txt and remove opencv config line it doesn't work.
So, question is - if I really need to include this opencv dependency in all derivative libs?
If you are linking it all via target_link_libraries and link them PUBLICly, dependencies should be transitive, look here.
Directory structure:
- src
-- CMakeLists.txt
-- ecu.cpp
-- engine_ecu.cpp
-- ...
- test
-- CMakeLists.txt
-- integration_test.cpp
src/CMakeLists.txt:
project(EngineController)
add_library(Lib1 SHARED
ecu.cpp
)
add_library(Lib2 SHARED
engine_ecu.cpp
load_detector.cpp
math_helper.cpp
temperature_sensor.cpp
)
target_link_libraries(Lib1
PUBLIC
EngineControllerApi
)
target_link_libraries(Lib2
PUBLIC
EngineControllerApi
Lib1
)
test/CMakeLists.txt:
project(EngineControllerTest)
add_executable(${PROJECT_NAME}
integration_test.cpp
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
Lib2
)
yields the following:
-- Build files have been written to: /diaggen/example/engine_controller/build
[ 11%] Building CXX object src/CMakeFiles/Lib1.dir/ecu.cpp.o
[ 22%] Linking CXX shared library libLib1.so
[ 22%] Built target Lib1
[ 33%] Building CXX object src/CMakeFiles/Lib2.dir/engine_ecu.cpp.o
[ 44%] Building CXX object src/CMakeFiles/Lib2.dir/load_detector.cpp.o
[ 55%] Building CXX object src/CMakeFiles/Lib2.dir/math_helper.cpp.o
[ 66%] Building CXX object src/CMakeFiles/Lib2.dir/temperature_sensor.cpp.o
[ 77%] Linking CXX shared library libLib2.so
[ 77%] Built target Lib2
[ 88%] Building CXX object test/CMakeFiles/EngineControllerTest.dir/integration_test.cpp.o
[100%] Linking CXX executable EngineControllerTest
[100%] Built target EngineControllerTest
I believe CMake should figure it out. First of all, make sure that you call find_package prior to referencing OpenCV at all. I believe that you could stick to target_link_libraries without having to alter PROPERTIES the way you do. Under the hood, I believe that target_link_libraries also modifies some PROPERTIES, but I believe it's much clearer this way.
Related
I'm trying to build a static library libbar with CMake. libbar should contain libfoo, i.e. all object files from subdirectory target libfoo should appear in libbar as well. The simplest dir tree is as follows:
bar
├── bar.cpp
├── CMakeLists.txt
└── foo
├── CMakeLists.txt
└── foo.cpp
Here is foo/CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(foo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(foo)
target_sources(foo PUBLIC foo.cpp)
And here is top CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(bar)
add_library(bar)
add_subdirectory(foo)
target_sources(bar PUBLIC bar.cpp)
target_link_libraries(bar PRIVATE foo)
In bar/ I do the following:
cmake . -Bbuild
cd build
cmake --build .
and I get
Scanning dependencies of target foo
[ 20%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.o
[ 40%] Linking CXX static library libfoo.a
[ 40%] Built target foo
Scanning dependencies of target bar
[ 60%] Building CXX object CMakeFiles/bar.dir/bar.cpp.o
[ 80%] Building CXX object CMakeFiles/bar.dir/foo/foo.cpp.o
[100%] Linking CXX static library libbar.a
[100%] Built target bar
As you can see, file foo.cpp was compiled twice, and I'm trying to get rid of this behavior. By the way, this method gives me a correct result:
$ ar t libbar.a
bar.cpp.o
foo.cpp.o
If I change PUBLIC into PRIVATE in foo/CMakeLists.txt, the build log is as follows:
Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target bar
[ 75%] Building CXX object CMakeFiles/bar.dir/bar.cpp.o
[100%] Linking CXX static library libbar.a
[100%] Built target bar
but foo.cpp.o doesn't get into libbar:
$ ar t libbar.a
bar.cpp.o
What is the correct way to build libbar containing libfoo without double compilation?
target_sources(foo PUBLIC foo.cpp)
This line forces targets that link to foo to include foo.cpp among their sources.
What is the correct way to build libbar containing libfoo without double compilation?
You have explicitly asked for this, so just... don't:
target_sources(foo PRIVATE foo.cpp)
PUBLIC means "apply to both self and linkees".
PRIVATE means "apply to self"
INTERFACE means "apply to linkees only"
If you really want foo.o to be in both archives (this is dubious) then you could use an OBJECT library that both libbar and libfoo link to.
add_library(foo_objs OBJECT foo.cpp)
# later ...
target_link_libraries(foo PRIVATE foo_objs)
# ...
target_link_libraries(bar PRIVATE foo_objs)
I've compiled a c++ dynamic library using cmake and I want to add to my iOS app. But the header file directory of this .framework is empty, I refer to the CMakeFiles written in the cmake documentation. I don't know where the problem is?
Any help would be greatly appreciated.
Here is my CMake script
cmake_minimum_required(VERSION 3.2)
project(Xml C CXX)
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR arm)
set(HEADERS
./include
)
include_directories(
${HEADERS}
)
aux_source_directory(. DIR_SRCS)
add_library(Xml SHARED
${DIR_SRCS}
${HEADERS}
)
set_target_properties(Xml PROPERTIES
FRAMEWORK TRUE
FRAMEWORK_VERSION CXX
PUBLIC_HEADER ${HEADERS}
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
)
Compilation progress
Scanning dependencies of target Xml
[ 10%] Building CXX object CMakeFiles/Xml.dir/ILock.cpp.o
[ 20%] Building CXX object CMakeFiles/Xml.dir/ParamSet.cpp.o
[ 30%] Building CXX object CMakeFiles/Xml.dir/StringConvert.cpp.o
[ 40%] Building CXX object CMakeFiles/Xml.dir/XmlFile.cpp.o
[ 50%] Building CXX object CMakeFiles/Xml.dir/XmlInterface.cpp.o
[ 60%] Building CXX object CMakeFiles/Xml.dir/tinystr.cpp.o
[ 70%] Building CXX object CMakeFiles/Xml.dir/tinyxml.cpp.o
[ 80%] Building CXX object CMakeFiles/Xml.dir/tinyxmlerror.cpp.o
[ 90%] Building CXX object CMakeFiles/Xml.dir/tinyxmlparser.cpp.o
[100%] Linking CXX shared library Xml.framework/Xml
Copying OS X content Xml.framework/Versions/CXX/Headers/include
[100%] Built target Xml
Compiled dynamic library
The issue is solved. CMake can't get all header files with the ./include syntax. The following is a modified CMake script.
set(HEADERS
./include/a.h
./include/b.h
./include/c.h
)
include_directories(
./include
)
aux_source_directory(. DIR_SRCS)
add_library(Xml SHARED
${DIR_SRCS}
${HEADERS}
)
set_target_properties(Xml PROPERTIES
FRAMEWORK TRUE
PUBLIC_HEADER "${HEADERS}"
)
Talking about a Qt 5.3.2 project which is buildt using cmake.
This is a calling order problem between UIC execution and target_link_libraries... unfortunately not in that order.
Below this text you will find
1.) a (still functional) excerpt section of my CMakeLists.txt and
2.) an excerpt of the the output of the command 'cmake .'
3.) the output of a following call to 'make' without using the
generated headers like 'ui_main.h'.
If (in the source of my library libqt.a) I require 'ui_main.h' the
make process crashes not finding the header. Looking at the
non-crashing make output shows why:
[..]
Scanning dependencies of target qt
[ 29%] Building CXX object CMakeFiles/qt.dir/home/kochmn/projects/sentinel/src/qt/form_main.cpp.o
[ 35%] Building CXX object CMakeFiles/qt.dir/qt_automoc.cpp.o
Linking CXX static library libqt.a
[..]
[ 52%] Generating ui_main.h
[..]
Make would generate libqt.a before generating the required header file.
So I experimented using code like
target_link_libraries(sentinel
${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES})
add_library(optimization "${DIR_SRC}/optimization/linalg.cpp")
add_library(qt "${DIR_SRC}/qt/form_main.cpp")
target_link_libraries(sentinel qt optimization)
to no avail. The question: How can I motivate cmake to first run UIC generating the ui-header files and then compiling my libqt.a?
Appendix
# 2.8.11 instead of 2.8 required for automatic linking to the qtmain.lib
# library if this ever should expand to Windows.
# (http://doc.qt.io/qt-5/cmake-manual.html)
cmake_minimum_required(VERSION 2.8.11)
project(sentinel)
set( CMAKE_AUTOMOC ON )
# CMake uses uic in order to generate header files from .ui forms from designer.
set ( CMAKE AUTOUIC ON )
# Auto-generating functions write their headers into the build directory.
# Hence the build directory should be included.
set( CMAKE_INCLUDE_CURRENT_DIR ON )
#> Getting the Qt essentials. ----------------------------------------
# Widgets finds its own dependencies (QtGui and QtCore).
find_package(Qt5Widgets REQUIRED)
message ("Found Qt5Widgets Version ${Qt5Widgets_VERSION_STRING}")
# All those darling variables are explained here:
# http://doc.qt.io/qt-5/cmake-manual.html
message("Core FOUND: ${Qt5Core_FOUND}")
message("Gui FOUND: ${Qt5Gui_FOUND}")
message("Widgets FOUND: ${Qt5Widgets_FOUND}")
message("Core VERSION: ${Qt5Core_VERSION_STRING}")
message("Gui VERSION: ${Qt5Gui_VERSION_STRING}")
message("Widgets VERSION: ${Qt5Widgets_VERSION_STRING}")
message("Core INCLUDE: ${Qt5Core_INCLUDE_DIRS}")
message("Gui INCLUDE: ${Qt5Gui_INCLUDE_DIRS}")
message("Widgets INCLUDE: ${Qt5Widgets_INCLUDE_DIRS}")
message("Core LIBRARIES: ${Qt5Core_LIBRARIES}")
message("Gui LIBRARIES: ${Qt5Gui_LIBRARIES}")
message("Widgets LIBRARIES: ${Qt5Widgets_LIBRARIES}")
message("Core DEFINITIONS: ${Qt5Core_DEFINITIONS}")
message("Gui DEFINITIONS: ${Qt5Gui_DEFINITIONS}")
message("Widgets DEFINITIONS: ${Qt5Widgets_DEFINITIONS}")
message("Core COMPILE_DEFINITIONS: ${Qt5Core_COMPILE_DEFINITIONS}")
message("Gui COMPILE_DEFINITIONS: ${Qt5Gui_COMPILE_DEFINITIONS}")
message("Widgets COMPILE_DEFINITIONS: ${Qt5Widgets_COMPILE_DEFINITIONS}")
message("Core EXECUTABLE_COMPILE_FLAGS: ${Qt5Core_EXECUTABLE_COMPILE_FLAGS}")
message("Gui EXECUTABLE_COMPILE_FLAGS: ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS}")
message("Widgets EXECUTABLE_COMPILE_FLAGS: ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
include_directories(
${Qt5Widgets_INCLUDE_DIRS} ${Qt5Core_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS})
#add_definitions(${Qt5Core_DEFINITIONS}) # Unnecessary. In Widgets.
#add_definitions(${Qt5Gui_DEFINITIONS}) # Unnecessary. In Widgets.
#< -------------------------------------------------------------------
set (DEBUG 1)
set (SENTINEL_NAME "Sentinel GL")
set (SENTINEL_VERSION_MAJOR "0")
set (SENTINEL_VERSION_MINOR "1")
set (SENTINEL_VERSION "${SENTINEL_VERSION_MAJOR}.${SENTINEL_VERSION_MINOR}")
## Compiler flags
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
# ${Qt5Core_EXECUTABLE_COMPILE_FLAGS} ${Qt5Gui_EXECUTABLE_COMPILE_FLAGS} #<-- redundant.
if(CMAKE_COMPILER_IS_GNUCXX)
message("Using GnuCXX compiler.")
add_definitions("-O0 -std=c++0x -lSOIL -llapacke -lblas")
endif()
if (DEBUG MATCHES 1)
message("\nBuilding DEBUG build.")
add_definitions(-Wall)
set(CMAKE_BUILD_TYPE Debug)
endif()
set(DIR_BASE "${PROJECT_SOURCE_DIR}/..")
set(DIR_SRC "${PROJECT_SOURCE_DIR}/../src")
set(DIR_RES "${PROJECT_SOURCE_DIR}/../resources")
set(DIR_BUILD "${PROJECT_SOURCE_DIR}/../build")
# Generated using uic FormMain.ui > ui_FormMain.h
set(qt_H
"${DIR_BUILD}/ui_main.h" "${DIR_BUILD}/ui_dialog_setup_game.h")
# Generated using the trusty QtDesigner.
set(qt_UI
"${DIR_SRC}/ui/main.ui" "${DIR_SRC}/ui/dialog_setup_game.ui")
# My own hand-written XML describing the internal resources.
set(qt_QRC "${DIR_RES}/application.qrc")
# generate rules for building source files that moc generates
QT5_WRAP_CPP(qt_H_MOC ${qt_H})
# generate rules for building header files from the ui files
QT5_WRAP_UI(qt_UI_H ${qt_UI})
# Resource Handling. QRC: "Qt Resource Collection"
QT5_ADD_RESOURCES(qt_RCCS ${qt_QRC})
# btw.: rcc generates a C program from ./resources/application.qrc
# However, this is not needed. cmake sees to that. :-)
#< -------------------------------------------------------------------
include_directories("${DIR_SRC}/include" "${PROJECT_SOURCE_DIR}")
add_executable(sentinel "${DIR_SRC}/sentinel.cpp" ${qt_H_MOC} ${qt_UI_H} ${qt_RCCS})
# Available modules are listed here: http://doc.qt.io/qt-5/qtmodules.html
# find /usr/lib/x86_64-linux-gnu/cmake -iname "*.cmake*" | less
# Note: http://stackoverflow.com/questions/20266235/cmake-error-qglwidget-no-such-file-or-directory
qt5_use_modules(sentinel Widgets Gui Core)
add_library(optimization "${DIR_SRC}/optimization/linalg.cpp")
add_library(qt "${DIR_SRC}/qt/form_main.cpp")
target_link_libraries(sentinel
${Qt5Widgets_LIBRARIES} ${Qt5Gui_LIBRARIES} ${Qt5Core_LIBRARIES}
qt optimization
)
kochmn#Ulyss:~/projects/sentinel/build$ cmake .
-- The C compiler identification is GNU 4.9.2
-- The CXX compiler identification is GNU 4.9.2
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
Found Qt5Widgets Version 5.3.2
Core FOUND: 1
Gui FOUND: 1
Widgets FOUND: 1
Core VERSION: 5.3.2
Gui VERSION: 5.3.2
Widgets VERSION: 5.3.2
Core INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Gui INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtGui;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Widgets INCLUDE: /usr/include/x86_64-linux-gnu/qt5/;/usr/include/x86_64-linux-gnu/qt5/QtWidgets;/usr/include/x86_64-linux-gnu/qt5/QtGui;/usr/include/x86_64-linux-gnu/qt5/QtCore;/usr/lib/x86_64-linux-gnu/qt5//mkspecs/linux-g++-64
Core LIBRARIES: Qt5::Core
Gui LIBRARIES: Qt5::Gui
Widgets LIBRARIES: Qt5::Widgets
Core DEFINITIONS: -DQT_CORE_LIB
Gui DEFINITIONS: -DQT_GUI_LIB;-DQT_CORE_LIB
Widgets DEFINITIONS: -DQT_WIDGETS_LIB;-DQT_GUI_LIB;-DQT_CORE_LIB
Core COMPILE_DEFINITIONS: QT_CORE_LIB
Gui COMPILE_DEFINITIONS: QT_GUI_LIB;QT_CORE_LIB
Widgets COMPILE_DEFINITIONS: QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB
Core EXECUTABLE_COMPILE_FLAGS: -fPIE
Gui EXECUTABLE_COMPILE_FLAGS: -fPIE
Widgets EXECUTABLE_COMPILE_FLAGS: -fPIE
Using GnuCXX compiler.
Building DEBUG build.
Sentinel GL -- C++ Project V 0.1.
(c) Markus-Hermann Koch, mhk#markuskoch.eu, 2015/04/28-?
Primary directory is /home/kochmn/projects/sentinel/build
System is Linux
Generating configuration header: "/home/kochmn/projects/sentinel/build/../build/mhk_cmake_config.h"
-- Configuring done
-- Generating done
-- Build files have been written to: /home/kochmn/projects/sentinel/build
kochmn#Ulyss:~/projects/sentinel/build$ make
Scanning dependencies of target optimization_automoc
[ 5%] Automatic moc for target optimization
[ 5%] Built target optimization_automoc
Scanning dependencies of target optimization
[ 11%] Building CXX object CMakeFiles/optimization.dir/home/kochmn/projects/sentinel/src/optimization/linalg.cpp.o
[ 17%] Building CXX object CMakeFiles/optimization.dir/optimization_automoc.cpp.o
Linking CXX static library liboptimization.a
[ 17%] Built target optimization
Scanning dependencies of target qt_automoc
[ 23%] Automatic moc for target qt
[ 23%] Built target qt_automoc
Scanning dependencies of target qt
[ 29%] Building CXX object CMakeFiles/qt.dir/home/kochmn/projects/sentinel/src/qt/form_main.cpp.o
[ 35%] Building CXX object CMakeFiles/qt.dir/qt_automoc.cpp.o
Linking CXX static library libqt.a
[ 35%] Built target qt
Scanning dependencies of target sentinel_automoc
[ 41%] Automatic moc for target sentinel
[ 41%] Built target sentinel_automoc
[ 47%] Generating qrc_application.cpp
[ 52%] Generating ui_main.h
[ 58%] Generating moc_ui_main.cpp
/home/kochmn/projects/sentinel/build/ui_main.h:0: Note: No relevant classes found. No output generated.
[ 64%] Generating ui_dialog_setup_game.h
[ 70%] Generating moc_ui_dialog_setup_game.cpp
/home/kochmn/projects/sentinel/build/ui_dialog_setup_game.h:0: Note: No relevant classes found. No output generated.
Scanning dependencies of target sentinel
[ 76%] Building CXX object CMakeFiles/sentinel.dir/home/kochmn/projects/sentinel/src/sentinel.cpp.o
[ 82%] Building CXX object CMakeFiles/sentinel.dir/moc_ui_main.cpp.o
[ 88%] Building CXX object CMakeFiles/sentinel.dir/moc_ui_dialog_setup_game.cpp.o
[ 94%] Building CXX object CMakeFiles/sentinel.dir/qrc_application.cpp.o
[100%] Building CXX object CMakeFiles/sentinel.dir/sentinel_automoc.cpp.o
Linking CXX executable sentinel
[100%] Built target sentinel
CMake generation order is computed from dependencies between files and targets. If your qt library depends on headers generated from .ui files, then you have to add ${qt_UI_H} in inputs of target qt:
QT5_WRAP_UI(qt_UI_H ${qt_UI})
[...]
add_library(qt "${DIR_SRC}/qt/form_main.cpp" ${qt_UI_H})
And CMake should normally execute UIC on .ui files before compiling libqt
By the way using target_link_libraries only set dependencies between targets at link time. At compile time, the normal behavior is "All source files should be found". In your case, some headers are generated, so setting these headers as input of a target ensures that the macro which generates them (QT5_WRAP_UI) will be executed before the compilation of the target.
I would like to install a certain set of headers (which is not identical to all headers in a directory) to an include directory during make install of my project.
Here is the file structure that I have:
MyProject
|-build
|-lib
|-include
|-src
|-A
| |-a1.cpp/.h
| |-a2.cpp/.h
| |-a3.cpp/.h
|
|-B
| |-b1.cpp/.h
| |-b1.cpp/.h
|
|-CMakeLists.txt
In MyProject/src/CMakeLists.txt (which is the main CMakeLists file), I setup my project and compile everything into a library.
During the install step (i.e. make install) I would like to move my build libmyproject.a to MyProject/lib and some headers, say A/a1.h and B/b1.h to the MyProject/include folder.
However, I want to maintain the relative paths of those headers!
I.e., I want to achieve this:
MyProject
|-build
|-lib
| |-libmyproject.a
|
|-include
| |-A
| | |-a1.h
| |
| |-B
| |-b1.h
|
|-src
|-...
Installing the library is easy with CMake:
set( CMAKE_INSTALL_PREFIX "path_to_my_project")
install(TARGETS myproject
ARCHIVE DESTINATION lib
)
Where I struggle is the headers. I have a simple list of my API headers:
set(my_api_headers
A/a1.h
B/b1.h
)
But I cannot simply use the 'install(FILES ...)' CMake command as that strips away the relative paths. All the other suggestions I have found so far involce the 'install(DIRECTORY ...)' form with a 'PATTERN', but I don't think I can use that as that
would copy all headers. (Compare, for example, How can I install a hierarchy of files using cmake?)
I tried a simple function
############################################################
#
# FUNCTION: install API header files
#
function(install_api_headers
API_HDRS
DST_DIR
)
foreach( _header ${${API_HDRS}} )
file(INSTALL ${_header}
DESTINATION ${DST_DIR}
)
endforeach( _header )
endfunction(install_api_headers)
#
############################################################
install_api_headers(my_api_headers "MyProject/include")
but that obviously (well, I remembered when I ran it... :/) is executed during CMake runtime and not during 'make install'...
Trying the easy fix with a 'install(CODE ...)' wrapper also didn't work... :(
install(CODE "install_api_headers(workmodel_API_HDRS
{CMAKE_INSTALL_PREFIX}/${include_DIR_NAME}/WorkModels/${workmodel_NAME})"
)
So, bottom line:Any hint, idea, link related on how to get this done would be greatly appreciated.
Thanks,
Claus
semipol.de/archives/251 appears to solve the issue:
From the link:
SET(HS folder/test.h folder/other/test2.h)
A simple call to INSTALL doesn’t preserve the folder structure:
INSTALL(FILES ${HS} DESTINATION include)
This results in all files being directly under $prefix/include.
To preserve the structure you can use this simple macro:
MACRO(INSTALL_HEADERS_WITH_DIRECTORY HEADER_LIST)
FOREACH(HEADER ${${HEADER_LIST}})
STRING(REGEX MATCH "(.*)[/\]" DIR ${HEADER})
INSTALL(FILES ${HEADER} DESTINATION include/${DIR})
ENDFOREACH(HEADER)
ENDMACRO(INSTALL_HEADERS_WITH_DIRECTORY)
INSTALL_HEADERS_WITH_DIRECTORY(HS)
I made an example which I thought solved the problem (my way :)):
https://dl.dropboxusercontent.com/u/68798379/cmake-install-example.tar.bz2
$ ./gen-linux.sh
-- The C compiler identification is GNU 4.8.2
..
$ cd linux/
$ make
Scanning dependencies of target LIBB
[ 20%] Building CXX object src/B/CMakeFiles/LIBB.dir/testB.cpp.o
[ 40%] Building CXX object src/B/CMakeFiles/LIBB.dir/internalB.cpp.o
Linking CXX static library libLIBB.a
[ 40%] Built target LIBB
Scanning dependencies of target LIBA
[ 60%] Building CXX object src/A/CMakeFiles/LIBA.dir/testA.cpp.o
[ 80%] Building CXX object src/A/CMakeFiles/LIBA.dir/internalA.cpp.o
Linking CXX static library libLIBA.a
[ 80%] Built target LIBA
Scanning dependencies of target TESTLIB
[100%] Building C object CMakeFiles/TESTLIB.dir/src/dummy.c.o
Linking C static library libTESTLIB.a
[100%] Built target TESTLIB
$ make install
[ 40%] Built target LIBB
[ 80%] Built target LIBA
[100%] Built target TESTLIB
Install the project...
-- Install configuration: ""
-- Installing: cmake-install-example/build/linux/../../lib/libTESTLIB.a
-- Installing: cmake-install-example/build/linux/../../include/testA.hpp
-- Installing: cmake-install-example/build/linux/../../include/testB.hpp
Highlights:
create two static libraries (LIBA, LIBB) which contain private header files.
merge the two libs defined in src into one final library (TESTLIB).
install the merged library into "lib" directory.
install only the specified header files into "include" directory.
Kindly notice what CMAKE_INSTALL_PREFIX is set to in the build/gen-linux.sh script.
I'm currently using CMake to build my project and CppUnit to Test it. In my CMake file i create two executables. sample is the compiled source itself. And with sample_test I run the tests. If i r
Here a part of my CMakeLists.txt
SET(SAMPLE_ROOT_PATH ${PROJECT_BINARY_DIR})
SET(SAMPLE_SOURCE_PATH ${SAMPLE_ROOT_PATH}/src)
SET(SAMPLE_TEST_SOURCE_PATH ${SAMPLE_ROOT_PATH}/test)
SET(SAMPLE_BIN_PATH ${SAMPLE_ROOT_PATH}/bin)
SET(SAMPLE_EXEC_NAME sample)
SET(SAMPLE_TEST_EXEC_NAME sample_test)
SET(EXECUTABLE_OUTPUT_PATH ${SAMPLE_BIN_PATH})
FILE(GLOB_RECURSE SAMPLE_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/*.cpp)
FILE(GLOB_RECURSE SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_PATH}/*.cpp)
SET(SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_FILES} ${SAMPLE_SOURCE_FILES}
)
LIST(REMOVE_ITEM SAMPLE_TEST_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/main.cpp)
SET(CMAKE_CXX_FLAGS "-g -Wall")
ADD_EXECUTABLE(${SAMPLE_EXEC_NAME} ${SAMPLE_SOURCE_FILES})
ADD_EXECUTABLE(${SAMPLE_TEST_EXEC_NAME} ${SAMPLE_TEST_SOURCE_FILES})
this is the output of make
[ 8%] Building CXX object CMakeFiles/sample.dir/src/KeyBuffer.cpp.obj
[ 12%] Building CXX object CMakeFiles/sample.dir/src/main.cpp.obj
[ 20%] Building CXX object CMakeFiles/sample.dir/src/Object.cpp.obj
[ 45%] Building CXX object CMakeFiles/sample.dir/src/World.cpp.obj
Linking CXX executable bin/sample.exe
[ 45%] Built target sample
[ 50%] Building CXX object CMakeFiles/sample_test.dir/test/KeyBufferTest.cpp.obj
[ 54%] Building CXX object CMakeFiles/sample_test.dir/test/ObjectTest.cpp.obj
[ 66%] Building CXX object CMakeFiles/sample_test.dir/src/KeyBuffer.cpp.obj
[ 75%] Building CXX object CMakeFiles/sample_test.dir/src/Object.cpp.obj
[100%] Building CXX object CMakeFiles/sample_test.dir/src/World.cpp.obj
Linking CXX executable bin/sample_test.exe
As you can see Object.cpp, World.cpp and KeyBuffer.cpp get compiled twice! How can i prevent it? Or is there a better way to handle the CppUnit tests using CMake?
Each target may have different compiler flags configured, so if you add one source files to two targets, separate object files need to be produced from this one source file for both targets.
The usual solution is to compile the shared source files into a static library which is then linked into both application targets.
add_library(base STATIC ${shared_SOURCES}) # except e.g. foo_main.cpp
add_executable(foo ${foo_only_SOURCES})
target_link_libraries(foo base)
add_executable(bar ${bar_only_SOURCES})
target_link_libraries(bar base)
Conceptually CMake treats each target (i.e., executable or library) as a separate build unit. The generated build system will produce an object file for each source file belonging to the target. By default CMake does not avoid redundant compilations of source files that are used in multiple targets, even if the compilation settings (compilation flags, preprocessor definitions ...) are exactly the same.
CMake 2.8.8 introduced a new feature called OBJECT_LIBRARY target to address the problem of avoiding redundant compilations:
To generate an object library use add_library:
FILE(GLOB_RECURSE SAMPLE_SOURCE_FILES ${SAMPLE_SOURCE_PATH}/*.cpp)
ADD_LIBRARY(sample_objects OBJECT EXCLUDE_FROM_ALL ${SAMPLE_SOURCE_FILES})
Other targets created by add_library or add_executable may reference the objects using an expression of the form $<TARGET_OBJECTS:objlib>:
ADD_EXECUTABLE(${SAMPLE_EXEC_NAME} $<TARGET_OBJECTS:sample_objects>)
FILE(GLOB_RECURSE SAMPLE_TEST_SOURCE_FILES ${SAMPLE_TEST_SOURCE_PATH}/*.cpp)
ADD_EXECUTABLE(${SAMPLE_TEST_EXEC_NAME} $<TARGET_OBJECTS:sample_objects> ${SAMPLE_TEST_SOURCE_FILES})
Compared with using a regular static library to avoid redundant compilation, an object library has the advantage that it does not need to be linked. On top of that it cannot be imported, exported or installed.