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.