In my situation I have two CMake projects (built using MSYS Makefiles if that matters):
I have created a bare-bones example below that demonstrates the bizarre issue I'm having. Simply put, app refuses to link when running make, but only if some Libzip code is left uncommented in mylib (which compiles and links fine, no matter what).
Zlib and Libzip source code is located in C:/Dev/Libs.
lib/CMakeLists.txt
cmake_minimum_required(VERSION 3.7)
# Set project
project(mylib)
set(LIBS_DIR "C:/Dev/Libs")
# Add mylib sources
include_directories("${CMAKE_CURRENT_SOURCE_DIR}/src")
file(GLOB_RECURSE SRCS "src/*.cpp")
add_library(mylib SHARED ${SRCS})
# Add Zlib
set(ZLIB_ROOT "${LIBS_DIR}/zlib-1.2.11")
include_directories(${ZLIB_ROOT})
target_include_directories(mylib PUBLIC ${ZLIB_ROOT})
file(GLOB ZLIB_SRCS "${ZLIB_ROOT}/*.c")
add_library(zlib STATIC ${ZLIB_SRCS})
# Add Libzip
set(LIBZIP_ROOT "${LIBS_DIR}/libzip-1.1.3")
include_directories("${LIBZIP_ROOT}/lib")
target_include_directories(mylib PUBLIC "${LIBZIP_ROOT}/lib")
file(GLOB LIBZIP_SRCS "${LIBZIP_ROOT}/lib/*.c")
add_library(libzip STATIC ${LIBZIP_SRCS})
set(LIBS_LINK zlib libzip)
set(LIBS_INSTALL zlib libzip)
set(LIBS_EXPORT zlib libzip)
target_link_libraries(mylib PUBLIC ${LIBS_LINK})
# https://rix0r.nl/blog/2015/08/13/cmake-guide/
# Define headers for this library. PUBLIC headers are used for
# compiling the library, and will be added to consumers' build
# paths.
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
$<INSTALL_INTERFACE:include>
PRIVATE src)
# 'make install' to the correct locations (provided by GNUInstallDirs).
include(GNUInstallDirs)
install(TARGETS mylib ${LIBS_INSTALL} EXPORT mylibConfig
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) # This is for Windows
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
# This makes the project importable from the install directory
# Put config file in per-project dir (name MUST match), can also
# just go into 'cmake'.
install(EXPORT mylibConfig DESTINATION share/mylib/cmake)
# This makes the project importable from the build directory
export(TARGETS mylib ${LIBS_EXPORT} FILE mylibConfig.cmake)
lib/src/lib.hpp
#pragma once
namespace lib
{
int func();
}
lib/src/lib.cpp
#include "lib.hpp"
#define ZIP_STATIC
#include "zip.h"
int lib::func()
{
zip_source_t *src;
zip_error_t error;
src = zip_source_buffer_create(0, 1, 0, &error);
return 10;
}
app/CMakeLists.txt
cmake_minimum_required(VERSION 3.7)
project(app)
# Add app sources
file(GLOB_RECURSE SRCS "src/*.cpp")
add_executable(app ${SRCS})
# Add mylib
set(mylib_DIR "${CMAKE_CURRENT_BINARY_DIR}/../lib")
find_package(mylib REQUIRED)
configure_file("${mylib_DIR}/libmylib.dll" "libmylib.dll" COPYONLY)
target_link_libraries(app mylib)
app/src/app.hpp
#pragma once
#include <lib.hpp>
app/src/app.cpp
#include <iostream>
#include "app.hpp"
int main()
{
std::cout << lib::func() << std::endl;
return 0;
}
Output from building mylib
$ make
[ 13%] Built target zlib
[ 98%] Built target libzip
Scanning dependencies of target mylib
[ 99%] Building CXX object CMakeFiles/mylib.dir/src/lib.cpp.obj
[100%] Linking CXX shared library libmylib.dll
[100%] Built target mylib
Output from building app
$ make
Scanning dependencies of target app
[ 50%] Building CXX object CMakeFiles/app.dir/src/app.cpp.obj
[100%] Linking CXX executable app.exe
CMakeFiles/app.dir/objects.a(app.cpp.obj):app.cpp:(.text+0x17): undefined reference to `lib::func()'
collect2.exe: error: ld returned 1 exit status
make[2]: *** [app.exe] Error 1
make[1]: *** [CMakeFiles/app.dir/all] Error 2
make: *** [all] Error 2
If I comment src = zip_source_buffer_create(0, 1, 0, &error);
in lib/src/lib.cpp, rebuild and then rebuild app:
$ make
-- Configuring done
-- Generating done
-- Build files have been written to: C:/Dev/Builds/cmaketest/app
[ 50%] Linking CXX executable app.exe
[100%] Built target app
$ ./app
10
Which yields the expected result.
The issue must lie in the CMakeLists of app, since mylib builds fine without any linking errors. Or am I adding zlib/libzip incorrectly in mylib? I need to link to them statically and I couldn't get it to work with find_package
.
Thanks!
Got it working after copying over the .dll.a file as well:
configure_file("${mylib_DIR}/libmylib.dll.a" "libmylib.dll.a" COPYONLY)
and prefixing all my methods in lib with the following:
__declspec(dllexport)