I'm trying to create a library that links against allegro5 media library using CMake. And then, I want to use my library in an executable.
My directory structure is:
src
|----core
|------src
|------tests
|------CMakeLists.txt
|----main.cpp
|----CMakeLists.txt
The CMakeLists.txt file inside the core folder is:
set(MY_HEADERS #My header files here)
set(MY_SRC #My source files here)
add_library(MyLib ${MY_HEADERS} ${MY_SRC})
target_include_directories(MyLib PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
## Allegro Lib
set(ALLEGRO_DIR "${PROJECT_SOURCE_DIR}/packages/allegro5/include")
if(WIN32)
file(GLOB ALLEGRO_LIB "${PROJECT_SOURCE_DIR}/packages/allegro5/windows/x86/lib/*.lib")
add_library(Allegro SHARED IMPORTED)
set_target_properties(Allegro PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES ${ALLEGRO_DIR}
IMPORTED_IMPLIB ${ALLEGRO_LIB}
)
target_link_libraries(MyLib PRIVATE Allegro)
file(GLOB ALLEGRO_DLL "${PROJECT_SOURCE_DIR}/packages/allegro5/windows/x86/bin/*.dll")
foreach(dll ${ALLEGRO_DLL})
add_custom_command(TARGET MyLib POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${dll} $<TARGET_FILE_DIR:MyLib>)
endforeach()
endif()
Now in my, top level CMakeLists.txt is:
cmake_minimum_required(VERSION 3.15)
project(MyProject)
enable_testing()
add_subdirectory(core)
add_executable(MyGame main.cpp)
target_link_libraries(MyGame MyLib)
In my IDE (Visual Studio) I see that the include statement for "allegro5/allegro.h" in my source files is inside core folder is giving me the warning "Cannot find directory allegro5 in search paths ... in context of ../src/main.cpp".
When I build the project I get the errors:
Cannot open source file 'allegro5/allegro'
Cannot open include file 'allegro5/allegro.h': No such file or directory.
This error only happens if I reference MyLib in main.cpp. (My main does not have any code, just a hello world statement):
// #include "MyLib.hpp"
int main(int argc, const char *argv[])
{
/*const auto engine = &MyLib::EngineManager::getInstance();
engine->start();
const auto display = &MyLib::DisplayManager::getInstance();
auto displayConfig = DisplayConfig();
displayConfig.fullscreen = false;
const auto displayId = display->createDisplay(displayConfig);*/
}
I guess this has something to do with the visibility I'm setting somewhere? I can't quite figure out how to fix. Appreciate your help, thanks!
EDIT:
When PRIVATE to PUBLIC, I get the following linker error:
LNK2019 unresolved external symbol __imp_al_install_system referenced in function "public: static void __cdecl mylib::EngineManager::start(void)" (?start#EngineManager#mylib##SAXXZ) C:\Users\xxx\src\out\build\x64-Debug\src C:\Users\xxx\src\out\build\x64-Debug\main.cpp.obj
The include directory for allegro5 is defined as ALLEGRO_DIR in your CMake:
${PROJECT_SOURCE_DIR}/packages/allegro5/include
Therefore, with the #include "allegro5/allegro.h", the full path to the header file would be appended:
${PROJECT_SOURCE_DIR}/packages/allegro5/include/allegro5/allegro.h
Be sure this path is correct and the file exists.
In addition, you set the INTERFACE include directories on the imported Allegro target, but you link it to MyLib using the PRIVATE keyword. This means the usage requirements of Allegro are not propagated to the MyGame. You should use PUBLIC for this link step instead if you want the INTERFACE_INCLUDE_DIRECTORIES of Allegro to also be transitively propagated to MyGame:
target_link_libraries(MyLib PUBLIC Allegro)
CMake has a good example demonstrating this in their documentation.
Related
I have the following folder structure in my c++ project
*--build
|---(building cmake here)
|
*--main.cpp
|
*--CMakeLists.txt (root)
|
*--modules
|---application
|------app.h
|------app.cpp
|------CMakeLists.txt
And the code below for both CMakeLists.txt files:
CMakeLists.txt (module)
cmake_minimum_required(VERSION 3.15.2)
file(GLOB APPLICATION_HEADERS *.h *.hpp)
file(GLOB APPLICATION_SRC *.c *.cpp)
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR})
CMakeLists.txt (root)
cmake_minimum_required(VERSION 3.15.2)
project(main)
enable_language(C CXX)
#set directories
set(CMAKE_BINARY_DIR build)
set(CMAKE_CONFIGURATION_TYPES UNIX)
set(CMAKE_MODULES_DIR ${SOURCE_DIR}/cmake)
add_executable(${PROJECT_NAME} main.cpp)
# Build sub-modules
include_directories(modules/application)
add_subdirectory(modules/application)
find_library(MY_APP_LIB app_lib REQUIRED)
target_link_libraries(${PROJECT_NAME} PUBLIC ${MY_APP_LIB})
However, when I do cmake .. in my build directory, it seems like my app library just doesn't build and it doesn't link to it. I end up with the following error:
CMake Error at CMakeLists.txt:80 (find_library):
Could not find MY_APP_LIB using the following names: app_lib
I tried looking at other stackoverflow questions but it seems like I'm missing something. Any help is appreciated!
Thanks!
You don't need to use find_* to locate the library. In fact you cannot locate the library this way, since find_library searches the file system for the library during configuration, i.e. before anything gets compiled.
There's good news though: If the targets are created in the same cmake project, you can simply use the name of the cmake target as parameter for target_link_libraries:
...
add_library(app_lib STATIC
${APPLICATION_HEADERS}
${APPLICATION_SRC})
# note: this should be a property of the library, not of the target created in the parent dir
target_include_directories(app_lib PUBLIC .)
...
add_subdirectory(modules/application)
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
You don't need to do find_library for your own targets, just link directly to app_lib:
target_link_libraries(${PROJECT_NAME} PUBLIC app_lib)
I am trying to work with CMake for the first time and am struggling to link header files into my main. My cmake directory looks like this:
Project
| CmakeLists.txt
| src
|| CMakeLists.txt
|| Main.cpp
| Libs
|| CMakeLists.txt
|| headers
|||obstacle_detection.hpp
||source
|||obstacle_detection.cpp
|build
||"build files"
I would like to link the files in the headers folder to main, but what I currently have does not appear to work. The following runs the CMake command correctly but fails to compile with the make command, being unable to find the given header file. My CMakeLists files are as follows:
Project:
cmake_minimum_required(VERSION 3.17)
project(Sensivision)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
find_package(OpenCV REQUIRED)
find_package(realsense2 REQUIRED)
find_library(darknet REQUIRED)
add_subdirectory(libs)
add_subdirectory(src)
target_link_libraries(${PROJECT_NAME} obstacle_detection)
Libs:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
src:
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
target_link_libraries(${PROJECT_NAME} ${realsense2_LIBRARY})
My include in main.cpp is
include <obstacle_detection.hpp>
I have also tried
include <headers/obstacle_detection.hpp>
and
include <obstacle_detection>
Each gives the error:
obstacle_detection.hpp: no such file or directory
What am I doing incorrectly to link the header to the main?
You haven't added any include directories to the obstacle_detection library. By listing the header file in the add_library call, this may allow the header to be displayed in an IDE, but it doesn't do anything for compilation. You should use target_include_directories to add the headers directory as an include directory for the obstacle_detection library. Otherwise, it, and other consuming targets, will have no knowledge of the headers in that directory.
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
# Add this line.
target_include_directories(obstacle_detection PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers)
# Not sure this line is necessary, as it doesn't appear you actually link anything...
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
You haven't shown the CMake code in the src directory, but be sure to link the obstacle_detection library target to the main target, e.g.:
target_link_libraries(MyExeTarget PRIVATE obstacle_detection)
In addition, because this header file is local, it is best if you use quotes to include the header:
#include "obstacle_detection.hpp"
You can use target_include_directories to add folder where your headers are located and #include <header.hpp> where needed.
Ex:
libs cmake:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_include_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
cpp:
#include <headers/obstacle_detection.hpp>
I've tried looking for an answer to this question. There are similar questions but none that answer mine.
I am trying to create a library that depends on a couple other external libraries. I have the external libraries as git submodules and compile them myself in CMake using add_subdirectory followed by target_link_library.
After doing that, I am able to use the external libraries and include their header files in any source file in my library that I have added using target_sources and also in any header file that at least one of these source files include.
For example, I have an external library glm and call target_sources(myLib PRIVATE Application.cpp) in my library. The header files in my library are added to the project using target_include_directories.
Now, I can do #include <glm/glm.hpp> in the Application.cpp file with no problems.
I also have an Application.hpp file that is included in the Application.cpp file. Because it is included, that allows me to do #include <glm/glm.hpp> in the Application.hpp file as well.
However, now I also have a Core.hpp file without a corresponding Core.cpp file. Because the Core.hpp file is not included in any source files, doing #include <glm/glm.hpp> throws an error that the file cannot be found.
This is my root CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(Ivory)
set(CMAKE_CXX_STANDARD 20)
add_library(${PROJECT_NAME} SHARED)
# Determine compiler platform (x32 or x64)
math(EXPR PLATFORM_BITS "8*${CMAKE_SIZEOF_VOID_P}")
set(PLATFORM "x${PLATFORM_BITS}")
# Determine target build platform
target_compile_definitions(${PROJECT_NAME}
PUBLIC
IVORY_WINDOWS
PRIVATE
IVORY_BUILD_DLL
)
# Set output directory
set(OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin/${CMAKE_SYSTEM_NAME}-${CMAKE_BUILD_TYPE}-${PLATFORM})
# Subdirectories
add_subdirectory(src)
add_subdirectory(tests)
add_subdirectory(executables)
target_include_directories(${PROJECT_NAME} PUBLIC include)
# External Libraries #
set(BUILD_SHARED_LIBS OFF)
# GLM
add_subdirectory(lib/glm)
target_link_libraries(${PROJECT_NAME} PRIVATE glm)
# GLEW
add_subdirectory(lib/glew)
target_link_libraries(${PROJECT_NAME} PRIVATE libglew_static)
# SFML
add_subdirectory(lib/SFML)
target_link_libraries(${PROJECT_NAME} PRIVATE sfml-window sfml-audio)
# SPDLOG
add_subdirectory(lib/spdlog)
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog)
# MinGW
target_link_libraries(${PROJECT_NAME} PRIVATE -static)
# Output Location
set_target_properties(${PROJECT_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${OUTPUT_DIRECTORY})
This is the src CMakeLists.txt:
target_sources(${PROJECT_NAME}
PRIVATE
Application.cpp
)
I am using CLion on Windows 10 with MinGW 7.3 compiler (64 bit).
What am I doing wrong?
If the Core.hpp header is meant to be included by clients and glm headers are called from this header the glm dependency in the target_link_libraries command must be PUBLIC not PRIVATE.
For the CMake documentation see here. For a more detailed explanation of the PUBLIC, PRIVATE, and INTERFACE keywords with examples see here.
I am trying to add an external .lib file to my project in Clion which uses CMake. My code is very simple and is simply to test whether the library gets included:
#include <iostream>
#include "header/test.h"
int main() {
test a; // returns error saying undefined reference to 'test::test()'
return 0;
}
When running this code I get the following error:
undefined reference to `test::test()'
This is because I am trying to make a test object however the library for test is not included.
The test.lib file and the test.h file are both in the "header" folder which is in the root of my project folder. The file path to this is F:\Project\header\
My Cmake text file is as follows:
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
add_executable(Project main.cpp)
target_link_libraries(Project
F:\\Project\\header\\test.lib)
In the cmake text file i use the line:
target_link_libraries(Project F:\Project\header\test.lib)
This should include the library file, however it doesn't seem to because I get the "undefined reference to..." error as mentioned above. The Cmake compiler does not give me an error.
You are conceptually correct, however you are not doing it in the CMake fashion. Check out the following links on how to link an external library.
CMake link to external library
cmake doesn't support imported libraries?
https://gitlab.kitware.com/cmake/community/wikis/doc/tutorials/Exporting-and-Importing-Targets
For your case, it would be as follows):
cmake_minimum_required(VERSION 3.14)
project(Project)
set(CMAKE_CXX_STANDARD 14)
# Import the library into the CMake build system
ADD_LIBRARY(test SHARED IMPORTED)
# Specify the location of the library
SET_TARGET_PROPERTIES(TARGET test PROPERTIES IMPORTED_LOCATION “/path/to/lib/test.dll”)
# create the executable
add_executable(Project main.cpp)
# Link your exe to the library
target_link_libraries(Project test)
The CMake documentation is very good. I recommend checking it out when you run into issues.
https://cmake.org/cmake/help/latest/command/add_library.html#imported-libraries
I'm using the submodule GitHub inside my project and now I want to use the target_include_directories for including the file inside the my project class
This is my cmake configuration
cmake_minimum_required(VERSION 3.9)
project(SpyCBlock)
set(CMAKE_CXX_STANDARD 14)
#bitcoin rpc lib
find_library(bitcoinapi 0.3 REQUIRED)
target_include_directories(rapidjson PUBLIC include/rapidjson/include)
target_include_directories(spycblockrpc PUBLIC include/spycblockrpc)
target_include_directories(btccryptography PUBLIC include/bitcoin-cryptography-library)
add_executable(
${PROJECT_NAME}
#other inclusion file cpp
#cpp-properties file include
include/cpp-properties/src/Properties.cpp
include/cpp-properties/src/PropertiesParser.cpp
include/cpp-properties/src/PropertiesUtils.cpp
#include bitcoin-cryptography-library
include/bitcoin-cryptography-library/cpp/Sha256.cpp
include/bitcoin-cryptography-library/cpp/Sha256Hash.cpp
include/bitcoin-cryptography-library/cpp/Utils.cpp
#include spycblocrpc
include/spycblockrpc/core/graph/TransactionGraph.cpp
include/spycblockrpc/core/graph/WrapperInformations.cpp
include/spycblockrpc/ConfiguratorSingleton.cpp
include/spycblockrpc/commands/DecodeScriptCommand.cpp
include/spycblockrpc/commands/DecodeRawTransaction.cpp
include/spycblockrpc/commands/HeightBlockchainCommand.cpp
include/spycblockrpc/commands/DecodeBlockAtIndexCommand.cpp
)
#bitcoin rpc lib
target_link_libraries(SpyCBlockTests bitcoinapi)
target_link_libraries(${PROJECT_NAME} bitcoinapi)
When run CMake I have this error
Starting to parse CMake project.
CMake Error at CMakeLists.txt:20 (target_include_directories):
Cannot specify include directories for target "rapidjson" which is not
built by this project.
CMake Error at CMakeLists.txt:22 (target_include_directories):
Cannot specify include directories for target "spycblockrpc" which is not
built by this project.
CMake Error at CMakeLists.txt:24 (target_include_directories):
Cannot specify include directories for target "btccryptography" which is
not built by this project.
CMake Error at CMakeLists.txt:26 (target_compile_definitions):
Cannot specify compile definitions for target "cppproperties" which is not
built by this project.
I'm new with the C++ and the cmake and I can't understand what I'm wrong
I want to add the solution to this problem, as suggested in the comments, the code has two problems:
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include/rapidjson/include)
The first argument of the target must be the name of the executable, so in this case, is SpyCBlock
The second problem is the definition of the target before the declaration of the target, the target_include_directories(SpyCBlock ...) is defined before the add_executable(${PROJECT_NAME} ...)
A minimal correct example is:
add_executable(
${PROJECT_NAME}
#other inclusion file cpp
#cpp-properties file include
include/cpp-properties/src/Properties.cpp
include/cpp-properties/src/PropertiesParser.cpp
include/cpp-properties/src/PropertiesUtils.cpp
#include bitcoin-cryptography-library
include/bitcoin-cryptography-library/cpp/Sha256.cpp
include/bitcoin-cryptography-library/cpp/Sha256Hash.cpp
include/bitcoin-cryptography-library/cpp/Utils.cpp
#include spycblocrpc
include/spycblockrpc/core/graph/TransactionGraph.cpp
include/spycblockrpc/core/graph/WrapperInformations.cpp
include/spycblockrpc/ConfiguratorSingleton.cpp
include/spycblockrpc/commands/DecodeScriptCommand.cpp
include/spycblockrpc/commands/DecodeRawTransaction.cpp
include/spycblockrpc/commands/HeightBlockchainCommand.cpp
include/spycblockrpc/commands/DecodeBlockAtIndexCommand.cpp
)
target_include_directories(${PROJECT_NAME} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>/include/rapidjson/include)
Now I can include the library like this <bitcoin-cryptography-library/Sha256.h>.