CMake: linking against a library linked to Qt5 - c++

I have a library which uses Qt5. I build it with this CMakeLists.txt file:
cmake_minimum_required (VERSION 3.0)
project (testLib LANGUAGES CXX)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
find_package(Qt5 REQUIRED Widgets)
add_library(testLib SHARED
src/TestClass.cpp
src/TestClass.h
)
target_include_directories(testLib PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/src
)
target_link_libraries(testLib PUBLIC Qt5::Widgets)
export(TARGETS testLib FILE testLib-exports.cmake)
Now I try to link an executable against this library in the build path. This is what I've tried so far:
cmake_minimum_required (VERSION 3.0)
project(TestProject)
add_executable(myexec src/main.cpp )
include(/path/to/testLib-exports.cmake)
target_link_libraries(myexec testLib)
I am getting this error:
Target "myexec" links to target "Qt5::Widgets" but the target was not
found. Perhaps a find_package() call is missing for an IMPORTED
target, or an ALIAS target is missing?
I don't want to explicitly use find_package() in myexec's cmake file, but want it to be transitive. How should I link against testLib then? If the answer is not in the build path it is fine.
EDIT: I changed the export line to:
export(TARGETS testLib FILE testLib-exports.cmake EXPORT_LINK_INTERFACE_LIBRARIES)
This seems to be exactly what I need, but the generated files with and without EXPORT_LINK_INTERFACE_LIBRARIES are identical. Both if them say
This file does not depend on other imported targets which have
been exported from the same project but in a separate export set.
As far as I understand, it should use testLib's target LINK_INTERFACE_LIBRARIES property, but I noticed that it is NOTFOUND. maybe this is the problem? However, INTERFACE_LINK_LIBRARIES has Qt5::Widgets.

Related

Deplying a C++ application on Linux- linking everything statically to simplify deployment?

I am building a C++ project from Github and want to deploy the code to a remote Linux machine. This is all new to me.
The project has a main.cpp, which includes the various headers/sources like a library.
The CMake outputs an executable (to represent main.cpp) AND a separate static library. The project also uses OpenSSL, which I have linked statically.
I presume the OpenSSL functions are included within the static library? So when I deploy, I don't need to copy-over or install any OpenSSL on the remote machine?
Is it possible to modify the CMake so the application and the library are merged in to one file?
I am trying to make deployment as simple as copying over a single file, if this is possible.
Any additional advice/references are most-welcome.
UPDATE the CMake script:
cmake_minimum_required(VERSION 3.20)
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
project(helloworld C CXX)
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_BUILD_TYPE Release)
set (BUILD_MAIN TRUE)
set (BUILD_SHARED_LIBS FALSE)
set (OPENSSL_USE_STATIC_LIBS TRUE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set( HELLOWORLD_HEADERS helloworld/File1.h helloworld/File2.h )
set( HELLOWORLD_SOURCES helloworld/File1.cpp helloworld/File2.cpp )
# Static library
add_library( helloworld ${HELLOWORLD_SOURCES} ${HELLOWORLD_HEADERS} )
# Rapidjson
include_directories(/tmp/rapidjson/include/)
# OpenSSL
if (NOT OPENSSL_FOUND)
find_package(OpenSSL REQUIRED)
endif()
add_definitions(${OPENSSL_DEFINITIONS})
target_include_directories(helloworld PUBLIC $<BUILD_INTERFACE:${OPENSSL_INCLUDE_DIR}>)
target_link_libraries(helloworld PRIVATE ${OPENSSL_LIBRARIES})
set( HELLOWORLD_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR})
include(GNUInstallDirs)
target_include_directories(helloworld PUBLIC
$<BUILD_INTERFACE:${HELLOWORLD_INCLUDE_DIRS}/>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/helloworld>
)
set_target_properties(helloworld PROPERTIES PUBLIC_HEADER "${HELLOWORLD_HEADERS}")
add_library(helloworld::helloworld ALIAS helloworld)
option(HELLOWORLD_INSTALL "Install HelloWorld" TRUE)
if (HELLOWORLD_INSTALL)
install(TARGETS helloworld
EXPORT helloworld
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/helloworld/
)
configure_file("${CMAKE_CURRENT_LIST_DIR}/helloworld-config.cmake.in" "${CMAKE_BINARY_DIR}/helloworld-config.cmake" #ONLY)
install(FILES "${CMAKE_BINARY_DIR}/helloworld-config.cmake" DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/helloworld")
install(EXPORT helloworld
FILE helloworld-targets.cmake
NAMESPACE helloworld::
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/helloworld
)
endif()
if (BUILD_MAIN)
add_executable(main main.cpp)
target_link_libraries(main helloworld)
endif()
ITNOA
I it is very helpful to make URL of your GitHub's project, but I write some public notes about that
In generally in CMake for static linking your library to your executable, you can write simple like below (from official CMake example)
add_library(archive archive.cpp zip.cpp lzma.cpp)
add_executable(zipapp zipapp.cpp)
target_link_libraries(zipapp archive)
In above example your executable file is just work without needing .a library file and you can simple copy single file.
if you want to make all of thing static, you make sure all dependencies make static link to your project, like CMake: how to produce binaries "as static as possible"
if you want to prevent library creation, Probably in your CMake file, you can find add_library command, and add_executable command. you can remove add_library command and add all sources to add_executable command.
for example add_executable(a.out main.cpp lib.cpp)

Cannot build cmake project with including directories in cmake project

|---Engine
|----CMakeList.txt
|----Engine.cpp
|----Engine.h
|---Models
|----CMakeList.txt
|----Snake.cpp
|----Snake.hpp
|---Type
|----CMakeList.txt
|----Point.hpp
|---CMakeList.txt
|---main.cpp
I just can't tell the main sheet that I want to add a directory with files to it ...
Each time, errors of the following type appear:
CMake Error at CMakeLists.txt: 12 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 13 (target_link_directories):
Cannot specify link directories for target "Snake" which is not built by
this project.
CMake Error at Engine / CMakeLists.txt: 8 (target_include_directories):
Cannot specify include directories for target "Snake" which is not built by
this project.
CMake Error at CMakeLists.txt: 17 (target_link_libraries):
Cannot specify link libraries for target "Snake" which is not built by this
project.
- Configuring incomplete, errors occurred!
Which, for several hours of intensified attempts, are not corrected in any way. Can anyone help with this?
CMakeLists.txt from Engine folder:
set(HEADERS
Engine.h)
set(SOURCES
Engine.cpp)
add_library(Engine ${HEADERS} ${SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
Main CMakeList.txt:
cmake_minimum_required(VERSION 3.16.3)
project(Snake)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(PROJECT_SOURCES
main.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC Engine)
target_link_directories(${PROJECT_NAME} PUBLIC Engine)
add_subdirectory(Engine)
target_link_libraries(${PROJECT_NAME} Engine)
add_executable(${PROJECT_NAME}
${PROJECT_SOURCES}
)
find_package(SFML 2.5.1 COMPONENTS graphics audio REQUIRED)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} sfml-graphics sfml-audio)
set(SFML_STATIC_LIBRARIES FALSE)
There are two errors. The first one is to call a PROJECT_NAME that hasn't been built yet. add_executable(${PROJECT_NAME} ...) and add_library(${PROJECT_NAME ...) should be used before the target_include_directories and target_link_directories that refers to it. Because, as #Stephen Newell noted, otherwise you will be using a PROJECT NAME that hasn't been declared/built yet.
The second error is that you are calling a PROJECT_NAME inside Engine/CMakeLists. Maybe you are missing a project(...) inside of it.
Maybe you should move set(SFML_STATIC_LIBRARIES FALSE) before linking it, as well.

Require shared library with dependencies in cmake

I'm new to cmake, so I'm having trouble figuring out how to model the following:
My program requires a third party library that I only have access to in the form of headers and *.so files. It also ships many of its dependencies as *.so files. How do I make sure that everything compiles and links correctly, ideally in the "correct" cmake way?
I've tried this
cmake_minimum_required (VERSION 3.8)
project ("Test")
add_executable (MyApp "MyApp.cpp")
link_directories("/path/to/lib")
target_include_directories(MyApp PUBLIC "/path/to/headers")
This compiles but fails at the linking stage.
Then I tried
cmake_minimum_required (VERSION 3.8)
project ("Test")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
add_executable (MyApp "MyApp.cpp")
find_package(Library REQUIRED)
target_link_libraries(MyApp PUBLIC Library::Library)
And cmake/FindLibrary.cmake following https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/ (truncated):
...
if(Library_FOUND AND NOT TARGET Library::Library)
add_library(Library::Library SHARED IMPORTED)
set_target_properties(Library::Library PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${Library_INCLUDE_DIR}"
)
set_target_properties(Library::Library PROPERTIES
IMPORTED_LOCATION "/path/to/library.so"
)
endif()
This compiles and links, but the required other *.so files are not found at runtime. I suppose I need to add them also as libraries somehow, although I don't want them to be exported in FindLibrary.cmake. How do I do this correctly?
You can use IMPORTED libraries:
add_library(externalLib SHARED IMPORTED GLOBAL)
set_property(TARGET externalLib PROPERTY IMPORTED_LOCATION "/path/to/lib.so")
target_include_directories(externalLib INTERFACE "/path/to/headers")
target_link_directories(externalLib INTERFACE /path/to/libs)
target_link_libraries(externalLib INTERFACE -ldep1 -ldep2)
Then you can just depend on it:
target_link_libraries(MyApp PRIVATE externalLib)

How to add cmake project to another cmake project as library?

I have been researching over hours but I still couldn't solve my problem.
This is Cmakelist of ProjectA. It perfectly works:
cmake_minimum_required(VERSION 3.5)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
project(ProjectA C CXX)
add_executable(ProjectA ${SOURCE_FILES_ProjectA})
target_link_libraries(ProjectA hts ${ZLIB} pthread)
target_compile_definitions(ProjectA PUBLIC -D_FILE_OFFSET_BITS=64 -DVERSION=\"${VERSION_STRING}\")
Now I want to add ProjectA to ProjectB as library but I got following error at first:
add_executable cannot create target "ProjectA" because another
target with the same name already exists. The existing target is a static
library created in source directory
Then, I changes cmakelist of projectB as below. Now makefile is created but it doesn't work. (I removed set(source_files) for simplicity)
ProjectB cmakelist:
include_directories(
${PROJECT_SOURCE_DIR}/lib
${PROJECT_SOURCE_DIR}/
${PROJECT_SOURCE_DIR}/lib/ProjectA)
add_library(ProjectA STATIC lib/ProjectA/src})
target_include_directories(ProjectA PUBLIC lib/ProjectA)
set_target_properties(ProjectA PROPERTIES LINKER_LANGUAGE CXX)
add_executable(ProjectB ${SOURCE_FILES})
target_link_libraries(ProjectB hts ${ZLIB} ProjectA pthread)
target_compile_definitions(ProjectB PUBLIC -D_FILE_OFFSET_BITS=64 -DVERSION=\"${VERSION_STRING}\")
Can you correct my cmakelist files, I am really lost in cmake syntax.

Can I make a library from multiple targets?

I'm trying to learn cmake and have started converting an old make project over to cmake. Here is a simplified version of the directory structure I now have:
CMakeLists.txt
src/
CMakeLists.txt
main.cpp
core/
CMakeLists.txt
/sourcecode, other cmakes, etc.
test/
CMakeLists.txt
someTest.cpp
Currently, in my root CMakeLists.txt file I simply have this:
cmake_minimum_required(VERSION 2.8)
project(all)
add_subdirectory(src)
add_subdirectory(test)
What I wanted to do, was have a library created by core/CMakeLists.txt that can be used by both src/CMakeLists.txt to build the main executable, but also loaded by test/CMakeLists to build the unit tests.
So my src/core/CMakeLists.txt file currently looks sort of like this:
cmake_minimum_required(VERSION 2.8)
project(core)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wpedantic -Wreorder -DBOOST_TEST_DYN_LINK -DBOOST_LOG_DYN_LINK ")
#some other directories in my core code:
add_subdirectory(display)
add_subdirectory(training)
add_subdirectory(utility)
#some packages I use...
find_package(Boost 1.55.0
COMPONENTS
log
program_options
serialization
thread
system
filesystem
REQUIRED)
find_package(GLUT REQUIRED)
find_package(OpenGL REQUIRED)
find_package(Eigen3 REQUIRED)
include_directories(
${PROJECT_SOURCE_DIR}
${EIGEN3_INCLUDE_DIR})
target_link_libraries(core
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
So the idea is that I now have a core target I can simply link against to run my tests, and everything should work. However, when I try to build main, for example, I get:
Cannot specify link libraries for target "core" which is not built by this
project.
I thought this might be because core doesn't have a add_library command, but if I add add_library(core) I get this error:
You have called ADD_LIBRARY for library core without any source files. This typically indicates a problem with your CMakeLists.txt file
But I don't want to add any source files; I just want this target to link the targets in the core directory and produce a target I can link against from test.
Clearly I'm missing some core knowledge here, either with cmake or the toolchain itself. Help is appreciated :)
If you only want to create a core target without source files, you need to declare it like an INTERFACE target. So, try to add the following code to your src/core/CMakeLists.txt:
cmake_minimum_required(VERSION 3.0) # REQUIRED 3.x.x version
project(core)
...
# Here declare your core_interface target
add_library(core_interface INTERFACE)
target_link_libraries(core_interface INTERFACE
display
training
utility
${Boost_LIBRARIES}
${OPENGL_LIBRARIES}
${GLUT_LIBRARY}
${OpenMP_LIBRARIES})
As you can see, if you make this, you'll need to upgrade your CMake installed version.
Then, you'll build your tests or any executable, linking with this interface target directly:
add_executable(main main.cpp)
target_link_libraries(main core_interface)