How to make QtCreator CMake build depend on another CMake project? - c++

I have a CMake project that produces a static library. It compiles fine in QtCreator and produces the library in build dir. The CMakeLists.txt for the static library looks like this:
cmake_minimum_required(VERSION 3.5)
project(mystaticlib VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
file(GLOB mystaticlib_SRC "src/**.cpp")
add_library( mystaticlib STATIC
${mystaticlib_SRC}
)
target_include_directories( mystaticlib PRIVATE include/mystaticlib INTERFACE include )
Now I have a Qt application project and I'd like to make it so that it depends on the other one - meaning I can do something like in the QtProject:
cmake_minimum_required(VERSION 3.25)
project(MyQtProject VERSION 0.1 LANGUAGES CXX)
# This is how I imagine it working, not an actual code
include_project(mystaticlib, "~/my_projects/mystaticlib/CMakeLists.txt")
set(HEADERS_mystaticlib get_project_headers(mystaticlib))
# end of made up code
add_executable(MyQtProjectEXE ${PROJECT_SOURCES})
target_link_libraries(MyQtProjectEXE mystaticlib)
target_include_directories(MyQtProjectEXE HEADERS_mystaticlib)
How can I get something like that? In practice, I'd like it to work so that the dependent project directory can be set to whatever during cmake configure step.

You are most likely interested in add_subdirectory.
If the containing subdirectory has a CMakeLists.txt then by:
add_subdirectory("./path/to/the/directory")
You will include all targets defined in that CMakeLists.txt file.
All you have to do is add a dependency by using target_link_libraries. CMake will then understand that the subdirectory needs to be build beforehand.
EDIT: To use your project as an example:
cmake_minimum_required(VERSION 3.25)
project(MyQtProject VERSION 0.1 LANGUAGES CXX)
# This is how I imagine it working, not an actual code
#if the path is a subdirectory within the current folder
add_subdirectory("./local_path/to/mystaticlib")
#if not you need to specify a binary dir
add_subdirectory("/absolute/path/to/mystaticlib" "${CMAKE_CURRENT_BINARY_DIR}/mystaticlib")
set(HEADERS_mystaticlib get_project_headers(mystaticlib))
# end of made up code
add_executable(MyQtProjectEXE ${PROJECT_SOURCES})
target_link_libraries(MyQtProjectEXE mystaticlib)
#...

Related

CMake BUILD undefined reference (findpng)

I'm still very new to CMake so feedback is definitely welcome. So, I'm trying to build a simple application that should eventually create a pdf using the library libharu.
I think i figured it out how to link the library. But I still receive build errors for the findpng module (I suppose libharu depends on it)
CMakeLists.txt:
cmake_minimum_required(VERSION 3.2.0 FATAL_ERROR) # current latest stable version (if lower give FATAL_ERROR)
project(pdf_generator VERSION 0.1.0) # name of the project, version.
file(GLOB TARGET_SRC "./src/*.cpp") # Creates variable, using globbing.
include_directories(${PROJECT_SOURCE_DIR}/include) # list of directories to be used as header search paths.
add_executable(main ${TARGET_SRC}) # Create an executable of set of source files [exe name files to bundle].
find_library(libhpdf_location NAMES libhpdf.a) # find the location of libhpdf.a and save the value in the variable libhpdf_location.
message(STATUS ${libhpdf_location}) # print status of variable.
add_library(libhpdf STATIC IMPORTED) # Add library via a static import.
set_target_properties(
libhpdf PROPERTIES
IMPORTED_LOCATION ${libhpdf_location}
)
target_link_libraries(main libhpdf)
I've never worked with that particular library before, but skimming their CMakeLists.txt on GitHub it seems like libharu has optional dependencies on libpdf and zlib. Without knowing how you built your version of libharu I'm going to assume that both are needed.
Luckily, CMake comes with find-modules for both libpng and zlib, so adding the following should work:
find_package(PNG REQUIRED)
find_package(ZLIB REQUIRED)
set_target_properties(libhpdf
PROPERTIES
INTERFACE_LINK_LIBRARIES "ZLIB::ZLIB;PNG::PNG"
)
Looks like all you need to do is tell cmake to link libpng.

Can values be set for CMake SOURCE(S) other than using set?

Suppose I have a simple C++ hello-world project with the following CMake script:
cmake_minimum_required(VERSION 3.15)
project(hello)
set(SOURCE main.cpp)
add_executable(${PROJECT_NAME} ${SOURCE})
Now I noticed that PROJECT_NAME is built-in and its value is set from project(*value*) but also SOURCE (and SOURCES) seems to be provided by CMake too.
Are there other ways where SOURCE can be assigned with project source files? Just like the same behavior with PROJECT_NAME. Or is set(SOURCE ...) the intended method.
I'm new to CMake. The SOURCE and SOURCES variables were colored out on my text editor. I'm confused.
Using a SOURCE variable is a common patter in CMake files, but it is not required.
The code above can be written without any variables, it would look something like this:
add_executable(hello main.cpp)
When there are a lot of source files, passing them all to add_executable can be inconvenient. Another alternative is target_sources:
add_executable(hello)
target_sources(hello PRIVATE main.cpp)

Support included directory in CLion

I have project in CLion constructed from 2 major parts(2 projects). One is dynamic library(/engine) and the second one is executable(/gui)
My project structure is:
CMakes looks like this:
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
add_subdirectory(engine)
add_subdirectory(gui)
/engine/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17)
add_library(enginelib SHARED library.cpp library.h)
/gui/CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
set(CMAKE_CXX_STANDARD 17)
include_directories(../engine)
add_executable(gui main.cpp)
target_link_libraries(gui PRIVATE enginelib)
Project builds correctly, gui is using engine and it works.
However Clion underscores including from engine and doesn't show things from engine.
How to fix this?
Thanks for help :)
Btw, It's my first time setting project like this, am I including the engine into gui correctly? Or there is a better way to do this?

Visual studio project for header only library

I'm creating a CMake project whose two main files are:
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(CPP_Algorithms_and_Data_Structures)
set( CMAKE_CXX_STANDARD 11 )
#add_subdirectory(./ElementaryAlgorithms)
add_subdirectory(./ElementaryDataStructures)
#add_subdirectory(./AdvancedDataStructures)
#add_subdirectory(./GraphAlgorithms)
#set(INCLUDE_FOLDERS
# ./
# ./ElementaryAlgorithms
# ./ElementaryDataStructures
# ./AdvancedDataStructures
# ./GraphAlgorithms)
set(INCLUDE_FOLDERS ./ ./ElementaryDataStructures)
set(HEADER_FILES alg-and-ds.h)
set(SRC_FILES main.cpp alg-and-ds.cpp)
add_executable(alg-and-ds ${SRC_FILES} ${HEADER_FILES})
target_include_directories(alg-and-ds PUBLIC ${INCLUDE_FOLDERS})
target_link_libraries(alg-and-ds elementary-data-structures)
#target_link_libraries(alg-and-ds
# graph-algorithms
# elementary-data-structures
# elementary-algorithms
# advanced-data-structures)
and
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(ElementaryDataStructures)
set( CMAKE_CXX_STANDARD 11 )
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL "Export all symbols")
endif()
add_library(elementary-data-structures INTERFACE)
target_include_directories(elementary-data-structures INTERFACE ./)
target_sources(elementary-data-structures INTERFACE
"${CMAKE_CURRENT_LIST_DIR}/list.h"
"${CMAKE_CURRENT_LIST_DIR}/list.tcc")
#set_target_properties(elementary-data-structures PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
I'm using these to generate a visual studio solution, however what I would like to do is to generate a separate project for the header only library.
Basically I had a small list library that I converted to an header only library, by using templates, before such change I was able to generate separate visual studio projects but in the same solution, in this case instead I can see something like this:
But what I'd like to see, assuming this is possible is a separate project for the ElementaryDataStructures.
I'm not an expert in CMake and all the setups, but I would be great if you could help me to figure out how to do it.
Update:
Following suggestion on the comment I got a new project in VS, however there's still a tiny bit that bothers me.
In the picture below I can see both alg-and-ds and ElementaryDataStructures_ referencing the same sources. Is there a way to avoid the alg-and-ds project to show such files?
The update CMakeLists.txt
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
project(ElementaryDataStructures)
set( CMAKE_CXX_STANDARD 11 )
if(WIN32)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS YES CACHE BOOL "Export all symbols")
endif()
add_library(elementary-data-structures INTERFACE)
target_include_directories(elementary-data-structures INTERFACE ./)
target_sources(elementary-data-structures INTERFACE
"${CMAKE_CURRENT_LIST_DIR}/list.h"
"${CMAKE_CURRENT_LIST_DIR}/list.tcc")
add_custom_target(ElementaryDataStructures_ SOURCES ${CMAKE_CURRENT_LIST_DIR}/list.h ${CMAKE_CURRENT_LIST_DIR}/list.tcc)
As far as I know there is no normal way to do it. Only a hackish one. So you create a custom target which will force MSVC to show the project in the solution tree. Something like this:
add_custom_target(${PROJECT_NAME}_ SOURCES ${PROJECT_SOURCES})
Note the underscore in the name: it is there to differentiate it from the name in the add_library command. Of course you need to replace the variables in my example to yours actual ones.
Another solution is to declare static library with stub source file:
file(TOUCH ${CMAKE_BINARY_DIR}/stub.cpp)
add_library(elementary-data-structures STATIC
"${CMAKE_BINARY_DIR}/stub.cpp"
"${CMAKE_CURRENT_LIST_DIR}/list.h"
"${CMAKE_CURRENT_LIST_DIR}/list.tcc"
)
target_include_directories(elementary-data-structures INTERFACE ./)

CMake: Build Multiple Executables in one Project with Static Library

I'm working on a project that consists of 3 server executables and one library for shared code. I want it to be cross-platform, so I'm using CMake (since Xcode is being a pain anyway) to handle the build process. I'm having trouble with setting up the CMakeLists so that I can include the library from a directory at the same level when I'm building the executable.
Here's the directory structure (and the CMake files):
tethealla2.0/
CMakeLists.txt
libtethealla/
CMakeLists.txt
encryption/
utils/
patch_server/
CMakeLists.txt
login_server/
CMakeLists.txt
ship_server/
CMakeLists.txt
My top-level CMake (tethealla2.0/CMakeLists.txt, only includes the sub-project that should compile):
project(tethealla CXX)
cmake_minimum_required(VERSION 2.6)
add_subdirectory(libtethealla)
add_subdirectory(patch_server)
tethealla2.0/libtethealla/CMakeLists.txt, which generates a static library:
project(Libtethealla C)
cmake_minimum_required(VERSION 2.6)
include_directories(encryption)
set(ENC_DR encryption/)
set(ENCRYPTION_SOURCES
${ENC_DR}/psobb-crypt.c
${ENC_DR}/psogc-crypt.c
${ENC_DR}/psobb-crypt.c
${ENC_DR}/encryption.c
)
add_library(tethealla STATIC ${ENCRYPTION_SOURCES})
tethealla2.0/patch_server/CMakeLists.txt thus far:
project(patch_server CXX)
cmake_minimum_required(VERSION 2.6)
add_executable(server main.cc)
target_link_libraries(server tethealla)
So it makes more sense if I build it from the top level since tethealla2.0/CMakeLists.txt will inherit the targets from each of the subdirectories and the one in patch_server will have access to the tethealla library. However what I want is to be able to build from within these subdirectories to generate Xcode projects so that I can work on/recompile them individually. To do so I need to be able to get to the libtethealla/build directory (where CMake outputs) to access the libtethealla.a library from patch_server. Is this possible?
On kind of another note, even in building from the top-level directory my source in patch_server can't include "encryption.h", the header file for the library in encryption. Which seems to be building fine. Any thoughts on that are also greatly appreciated!
My solution is to use add_subdirectory with relative patch to shared_lib directory. I don't think that this is a perfect solution it has its caveats:
Logic very similar to a header guard must be added to library CMakeLists.txt to prevent from defining targets multiple times.
Each CMakeList.txt file must know the relative path to the library, if one want to move library all CMakeLists must be updated.
Let's assume that the directory structure looks like this:
root/
CMakeLists.txt
shared_lib/
CMakeLists.txt
inc/
foo.h
src/
foo.c
exec1/
CMakeLists.txt
main.c
exec2/
CMakeLists.txt
main.c
root/CMakeList.txt
cmake_minimum_required(VERSION 2.6)
add_subdirectory(shared_lib)
add_subdirectory(exec1)
add_subdirectory(exec2)
I have decided that shared_lib/CMakeLists.txt will export a variable named SHARED_DIR_INCLUDE_DIR. This approach helps to decouple things a little bit.
root/exec1/CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
add_subdirectory(./../shared_lib shared_lib)
include_directories(${SHARED_LIB_INCLUDE_DIR})
set(SRCS main.c)
add_executable(exec1 ${SRCS})
target_link_libraries(exec1 shared_lib)
if() in the fourth line solves the issue with target's multiple definition in case the CMakeLists file is added multiple times. The second and the third lines exports the include directory for library in SHARED_LIB_INCLUDE_DIR
root/shared_lib/CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
set(SHARED_LIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/inc)
set(SHARED_LIB_INCLUDE_DIR ${SHARED_LIB_INCLUDE_DIR} PARENT_SCOPE)
if(TARGET shared_lib)
message("shared_lib is already defined")
else()
include_directories(${SHARED_LIB_INCLUDE_DIR})
set(LIB_SRCS ./src/foo.c)
add_library(shared_lib STATIC ${LIB_SRCS})
endif()