Cmake - how to inject source file into subdirectory project - cmake

I have a cmake project leveraging another cmake library project, the dir looks like this:
/CMakeList.txt
/main.c
/.gitmodules
/patch/patch.c
/vendor/CMakeList.txt
/vendor/vendor.c
/vendor/...
In /CMakeList.txt, I used add_subdirectory(vendor) to include/link vendor library to my own project.
In /vendor/CMakeList.txt, source file is added by FILE(GLOB SRC_VEN vendor.c ...)
I want to inject /patch/patch.c into vendor library without touching /vendor directory, which is a git submodule
Is it possible to use cmake to achieve this in my root CMakeList.txt?
Thanks!

Turning my comment into an answer
If you want to inject sources into an existing target you can use target_sources() (introduced with CMake version 3.1).
In your case this would look something like:
/CMakeLists.txt
...
add_subdirectory(vendor)
target_sources(vendor_target PRIVATE "patch/patch.c")
I put vendor_target as a placeholder. Please replace it with the real name for the target you want to inject the sources into.
For more details see e.g. here.

Related

How do I specify a specific CMake target as a dependency?

Our CMake project, hosted on GitHub, has a CMake git submodule as a dependency. The file structure, then, is roughly:
project/
CMakeLists.txt
extern/
big_lib/
CMakeLists.txt
include/
*.hpp
static/
CMakeLists.txt
shared/
CMakeLists.txt
We have authorship of both project and big_lib.
The top level CMakeLists.txt for project includes something like:
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/big_lib)
target_link_libraries(${PROJECT_NAME} big_lib::static)
big_lib::static is a library we don't install/publish; it's not specified as such in the big_lib configuration, it's for internal consumption only - namely for tests. We deliver a client facing shared library, but the shared library is not appropriate for project.
This is why ExternalProject_Add may not be the most appropriate solution for satisfying our dependency - as it is my understanding installing the dependency in the build directory won't install the specific build target we need. Also, I haven't had luck getting it to work yet.
What I've also noticed is that we're building all targets in big_lib, of which there are hundreds - mostly tests, and that shared library I don't want or need. I suspect this is because we're including the entire library from it's base directory.
I've tried:
add_subdirectory(${PROJECT_SOURCE_DIR}/extern/big_lib/static)
But it seems there's configuration from the big_lib base directory that now goes unspecified, which is why I'm including the base directory in project instead of this.
So my questions are:
Is there a better way to specify the static build target so only that gets built?
Is there a better way to organize the configuration of big_lib so I can add only the static library as the dependency folder, and not duplicate configuration from the base directory between static and shared?
What options am I not aware of? Maybe I should use ExternalProject_Add and specify some sort of custom build command where I issue just the static lib as the build target and install target, and then link against that artifact?

How to set a specific package path for CMakeLists.txt

My colleague wrote a CMakeLists.txt, which contains things as below:
find_package(OpenCV 3 REQUIRED
COMPONENTS
opencv_core
opencv_imgproc
opencv_imgcodecs
CONFIG
)
As the project needs these components of Opencv3, my colleague downloaded the whole Opencv3, of course, it works.
But the whole Opencv3 is too big, so I get only the necessary lib files: libopencv_core.so, libopencv_imgproc.so and libopencv_imgcodecs.so and try to replace the whole Opencv3. The three so files are put here: /opt/opencv3/.
I don't know how to tell the CMakeLists.txt to look for the components of Opencv3 at the specific path instead of the path by default.
I'm totally a newbie on writing CMakeLists.txt...
CMake find_package() finds and configure project dependencies in CMake using two modes of operation, Module and Config, as described in its documentation.
In Module mode (not your case), it looks for a Find<package>.cmake file inside CMAKE_MODULE_PATH. This file searches for header files and libraries and set the necessary CMake variables in case of success.
In your case it is using Config, as requested by the CONFIG keyword. In Config mode CMake looks for for a <name>Config.cmake file or <lowercase-name>-config.cmake.
These config files describe the version of the dependency and the location of header files and library modules.
So you should look for OpenCVConfig.cmake or opencv-config.cmake in CMAKE_PREFIX_PATH or in OpenCV_DIR.
Please note that you have to set(OpenCV_DIR ...) before calling find_package().

How do I include src files from a library I have written into cmake of android project

Essentially I have written a library in c++ which i would like to use in my android application and I have yet to find a way to include files from folders in the parent directory.
Projects Directory
my_c++_project
src/
cpp and header files
Android Application/
App/
CMakeList
src/
If you're looking for a quick solution, then you will want to use target_include_directories that can be used like this:
target_include_directories(androi_app PUBLIC ${MY_CPP_PROJ_INCLUDE_DIR})
You then generate your android application using something like this
cmake ../ -DMY_CPP_PROJ_INCLUDE_DIR=/your/cpp/proj/src/folder
However, I would suggest to instead use CMake to generate the necessary build files for your my_c++_project. Once you have the proper setup, you can simply use target_link_libraries(my_android_app my_cpp_proj) (assuming your c++ project is called my_cpp_proj).
Here's a fairly minimal example of a CMake project which you can use for your my_c++_project.

cmake dependency between two projects at the same level

In my CMake project I have two 3rd party libraries which are required.
The problem is that the second one requires the first one to be build first.
To be precise I have the following structure
-project
CMakeLists.txt // add_subdirectory(first_lib)
// add_subdirectory(second_lib)
- first_lib
CMakeLists.txt // ...
- second_lib
CMakeLists.txt // ..
// contains find_package(first_lib REQUIRED)
// ..
This project cannot build because the first library must be build first and installed to make available its package.
What's the best way to deal with this case in CMake?
You can make second_lib depend on target name of first_lib. This will force first_lib to be build first.
To avoid modification of CMakeLists.txt of second_lib you can use the following solution:
Create a custom Findfirst_lib.cmake module. Set any first_lib-related variables expected by second_lib inside the module.
set(FIRST_LIB_LIBRARIES first_lib) #use *first_lib* target name here.
set(FIRST_LIB_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/first_lib/include)
Do not forget to add the module's directory to CMAKE_MODULE_PATH.
This solution assumes that second_lib uses the variables, set by Findfist_lib module, in target_link_libraries, target_include_directories etc. Like:
target_link_libraries(second_lib ${FIRST_LIB_LIBRARIES})
I have not found a way to make it work with imported targets.
I found an answere here using
add_dependencies()
Force building external project (with buildtools) before main project with CMake

CMake package configuration files for upstream projects using Qt5 problems

I am working on a larger C++ library that is using CMake and depends on Qt.
We moved from Qt4 to Qt5 and now I encounter a problem when using our lib
in an upstream project. As a minimal working example demonstrating the problem please have a look at this repo:
https://github.com/philthiel/cmake_qt5_upstream
It contains two separate CMake projects:
MyLIB: a tiny library that uses QString from Qt5::Core.
It generates and installs package configuration files
MyLIBConfig.cmake, MyLIBConfigVersion.cmake, and MyLIBTargets.cmake
in order to be searchable by CMake find_package()
MyAPP: a tiny executable depending on MyLIB
The project uses find_package(MyLIB) and creates an executable that uses MyLIB
The problem is that CMake gives me the following error message when configuring the MyAPP project:
CMake Error at CMakeLists.txt:11 (add_executable):
Target "MyAPP" links to target "Qt5::Core" but the target was not found.
Perhaps a find_package() call is missing for an IMPORTED target, or an
ALIAS target is missing?
The reason for this behaviour is that in the automatically generated MyLIBTargets.cmake file the INTERFACE_LINK_LIBRARIES entry for Qt5 Core is the Qt5::Core symbol. Using Qt4, the absolute path to the Qt core lib was specified here.
Now, I simply can resolve this by using
find_package(Qt5Core 5.X REQUIRED)
in the MyAPP project.
However, I would like to know if this is the intended/generic way to go, i.e. requesting upstream projects of our lib to search for the required transitive Qt5 dependencies themselves, or if I probably misuse CMake here and need to change my configuration procedure?
The CMake docu on package file generation
https://cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html
mentions that macros can be provided by the package configuration files to upstream. Maybe this would be the correct place to search for imported targets like Qt5 and break upstream configuration runs when these dependencies are not found?
Best,
Philipp
[edit of the edit] Full Source Example
You need to deliver a CMake config file for your project, and probably the ConfigFile should be generated via CMake itself (because you cannot know for shure where the user will install your software).
Tip, use the ECM cmake modules to ease the creation of that:
find_package(ECM REQUIRED NO_MODULE)
include(CMakePackageConfigHelpers)
ecm_setup_version(${PROJECT_VERSION}
VARIABLE_PREFIX ATCORE
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/atcore_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfigVersion.cmake"
SOVERSION 1
)
configure_package_config_file("${CMAKE_CURRENT_SOURCE_DIR}/KF5AtCoreConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5AtCoreConfig.cmake"
INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR}
)
and the KF5AtCoreConfig.cmake.in:
#PACKAGE_INIT#
find_dependency(Qt5Widgets "#REQUIRED_QT_VERSION#")
find_dependency(Qt5SerialPort "#REQUIRED_QT_VERSION#")
find_dependency(KF5Solid "#KF5_DEP_VERSION#")
include("${CMAKE_CURRENT_LIST_DIR}/KF5AtCoreTargets.cmake")
This will generate the correct FindYourSortware.cmake with all your dependencies.
[edit] Better explanation on what's going on.
If you are providing a library that will use Qt, and that would also need to find the Qt5 library before compilling the user's source, you need to provide yourself a FindYourLibrary.cmake code, that would call
find_package(Qt5 REQUIRED COMPONENTS Core Gui Widgets Whatever)
Now, if it's your executable that needs to be linked, use the Components instead of the way you are doing it now.
find_package(Qt5 REQUIRED COMPONENTS Core)
then you link your library with
target_link_libraries(YourTarget Qt5::Core)