How to specify the output directory of a given DLL? - windows

I'm using the following src/CMakeLists.txt:
cmake_minimum_required(VERSION 3.1.0)
project(foo)
add_library(foo SHARED foo.cpp)
set_target_properties(foo
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/subdir
)
And on Windows, I'm building the library using:
mkdir build
cd build
cmake ../src
cmake --build .
Output File: ~/build/Debug/foo.dll
Expected Output File: ~/build/Debug/subdir/foo.dll
What am I doing wrong?
It works fine on platforms other than Windows, and it seems like it should work according to the following documentation:
add_library
set_target_properties
LIBRARY_OUTPUT_DIRECTORY
cmake-generator-expressions.

Short answer
On Windows, unlike other platforms, you should use RUNTIME_OUTPUT_DIRECTORY instead of LIBRARY_OUTPUT_DIRECTORY to specify the output directory of a shared library.
Long answer
This is documented on the CMake documentation about Output Artifacts:
Runtime Output Artifacts
A runtime output artifact of a buildsystem
target may be:
The executable file (e.g. .exe) of an executable target created by the
add_executable() command.
On DLL platforms: the executable file (e.g.
.dll) of a shared library target created by the add_library() command
with the SHARED option. The RUNTIME_OUTPUT_DIRECTORY and
RUNTIME_OUTPUT_NAME target properties may be used to control runtime
output artifact locations and names in the build tree.
Library Output Artifacts
A library output artifact of a buildsystem
target may be:
The loadable module file (e.g. .dll or .so) of a module library target
created by the add_library() command with the MODULE option.
On
non-DLL platforms: the shared library file (e.g. .so or .dylib) of a
shared library target created by the add_library() command with
the SHARED option. The LIBRARY_OUTPUT_DIRECTORY and
LIBRARY_OUTPUT_NAME target properties may be used to control library
output artifact locations and names in the build tree.
But why would CMake make such a difference between DLL platforms (Windows) and non-DLL platforms (macOS, Linux, etc.)?
I couldn't find a source documenting this design decision, but I believe the rationale is that Windows does not support the concept of rpath, that is, .exe files can't store internally the location of their dependent .dll files. Therefore, on Windows, .dll files are often stored in the same folder as .exe files to make sure that the DLLs are found at runtime. Instead, on Unix systems, shared library files are often stored in a separate lib folder, while application binaries are stored in a bin folder, which is not a problem because binaries can store the location of their dependencies using rpath.
In conclusion, it makes sense for cross-platform development to define both LIBRARY_OUTPUT_DIRECTORY and RUNTIME_OUTPUT_DIRECTORY, like so:
cmake_minimum_required(VERSION 3.1.0)
project(foo)
add_library(foo SHARED foo.cpp)
set_target_properties(foo
PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/lib
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/$<CONFIG>/bin
)

Related

missing .lib file when creating shared library with cmake and visual studio 2019 generator

I have created a personnal C++ library and I try to use it in an other program. To create and compile my library, I use the commands
cmake -G "Visual Studio 16 2019" -A x64 ..
cmake --build . --config Release --target INSTALL
I have no problem with te compilation and the installation, but in the Target-release.cmake install look like this :
#----------------------------------------------------------------
# Generated CMake target import file for configuration "Release".
#----------------------------------------------------------------
# Commands may need to know the format version.
set(CMAKE_IMPORT_FILE_VERSION 1)
# Import target "containers" for configuration "Release"
set_property(TARGET containers APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
set_target_properties(containers PROPERTIES
IMPORTED_IMPLIB_RELEASE "C:/Program Files (x86)/containers/lib/containers.lib"
IMPORTED_LOCATION_RELEASE "C:/Program Files (x86)/containers/bin/containers.dll"
)
list(APPEND _IMPORT_CHECK_TARGETS containers )
list(APPEND _IMPORT_CHECK_FILES_FOR_containers "C:/Program Files (x86)/containers/lib/containers.lib" "C:/Program Files (x86)/containers/bin/containers.dll" )
# Commands beyond this point should not need to know the version.
set(CMAKE_IMPORT_FILE_VERSION)
Nothing abnormal, as far as I can see. My problem is : I have no file C:/Program Files (x86)/containers/lib/containers.lib generated during the compilation and the installation. So every time I try to use a find package, I have an error. (It's only with visual studio generator, it works with mingw). Here is my CMakeLists.txt :
cmake_minimum_required(VERSION 3.1)
set(VERSION 1.0.0)
project (containers
VERSION ${VERSION}
DESCRIPTION "Library adding some features to containers of the stl."
LANGUAGES CXX)
option(BUILD_TESTING "Build test programs" OFF)
include(CTest)
# Set the possible values of build type for cmake-gui
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build.")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
message( STATUS "Sources path : ${PROJECT_SOURCE_DIR}")
message( STATUS "Binary path : ${PROJECT_BINARY_DIR}")
message( STATUS "install path : ${CMAKE_INSTALL_PREFIX}")
message( STATUS "Version : ${PROJECT_VERSION}")
message( STATUS "Version : ${PROJECT_VERSION}")
message( STATUS "Compiler : ${CMAKE_CXX_COMPILER_ID}")
set(SOURCES ${PROJECT_SOURCE_DIR}/src/containers.cpp)
set(HEADERS ${PROJECT_SOURCE_DIR}/include/containers/containers_check.h
${PROJECT_SOURCE_DIR}/include/containers/containers.h
${PROJECT_SOURCE_DIR}/include/containers/append.h
${PROJECT_SOURCE_DIR}/include/containers/contains.h
${PROJECT_SOURCE_DIR}/include/containers/remove.h
${PROJECT_SOURCE_DIR}/include/containers/print.h
)
add_library(containers SHARED ${SOURCES} ${HEADERS})
#add_library(containers INTERFACE)
target_compile_features(containers PRIVATE cxx_std_17)
set_target_properties(containers
PROPERTIES
MSVC_RUNTIME_LIBRARY "MultiThreadedDLL"
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS OFF)
target_include_directories(containers
PUBLIC
$<INSTALL_INTERFACE:include>
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>)
target_compile_options(containers PRIVATE
# g++
#$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Wall>>
#$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Wextra>>
#$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-pedantic>>
#$<$<CXX_COMPILER_ID:GNU>:$<BUILD_INTERFACE:-Werror>>
#$<$<CXX_COMPILER_ID:GNU>:-Wno-reorder>
## Clang
#$<$<CXX_COMPILER_ID:Clang>:$<BUILD_INTERFACE:-Wall>>
##TODO
## MSVC
#$<$<CXX_COMPILER_ID:MSVC>:$<BUILD_INTERFACE:/W4>>
#$<$<CXX_COMPILER_ID:MSVC>:$<BUILD_INTERFACE:/WX>>
)
install(TARGETS containers
EXPORT containersTarget
ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ COMPONENT Development
LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/ COMPONENT Library NAMELINK_COMPONENT Development
RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin/ COMPONENT Runtimes
)
install(FILES ${HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/containers/
COMPONENT headers)
include(CMakePackageConfigHelpers)
# For moteur_de_calculConfig.cmake
set(INCLUDE_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/include CACHE PATH "install path for include files")
set(LIBRARY_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib CACHE PATH "install path for libraries")
#------------------------------------------------------------------------------
# Configure <export_config_name>ConfigVersion.cmake common to build and install tree
set(config_version_file ${PROJECT_BINARY_DIR}/containersConfigVersion.cmake)
write_basic_package_version_file(
${config_version_file}
VERSION "${CMAKE_PROJECT_VERSION}"
COMPATIBILITY ExactVersion
)
#------------------------------------------------------------------------------
# Export '<export_config_name>Target.cmake' for a build tree
export(TARGETS
containers
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Target.cmake"
)
#------------------------------------------------------------------------------
# Configure '<export_config_name>Config.cmake' for a build tree
set(build_config ${CMAKE_BINARY_DIR}/containersConfig.cmake)
configure_package_config_file(
"containersConfig.cmake.in"
${build_config}
INSTALL_DESTINATION "${PROJECT_BINARY_DIR}"
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR VERSION
)
#------------------------------------------------------------------------------
# Export '<export_config_name>Target.cmake' for an install tree
install(EXPORT
containersTarget
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
)
#------------------------------------------------------------------------------
# Configure '<export_config_name>Config.cmake' for a install tree
set(install_config ${PROJECT_BINARY_DIR}/CMakeFiles/containersConfig.cmake)
configure_package_config_file(
containersConfig.cmake.in
${install_config}
INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR VERSION
)
# Install config files
install(
FILES ${config_version_file} ${install_config}
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/cmake/${PROJECT_NAME}"
)
# test
if(BUILD_TESTING)
add_subdirectory(test)
endif()
# uninstall target
# use : make uninstall
if(NOT TARGET uninstall)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE #ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif()
My cmake version :
cmake version 3.18.0
What is missing in my CMakeLists.txt for generate the container.lib file ?
Faced the same problem, I found the solution here: for Visual Studio to export symbols in a .lib file besides the .dll library, you need to set this in your CMake (version>= 3.4) script:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
Note that the .lib file created this way is a small size file and is not a static library.
CMake manual
I'd like to add to the accepted answer here, for others who might find it: although CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS will solve the problem, it could well be a sticking plaster masking a deeper issue going on with your code.
I'm not an expert on the Microsoft compilers, but I do know that if you build a shared library with MSVC, the .lib file should still be produced. However, rather than containing all of your compiled code as it would for a static library, it basically provides the compiler with information about the exported symbols in your shared library. This means that the compiler can automatically link any other targets to your shared library, without you needing to manually load the library from your code using the Windows API functions. If you link an executable to a shared library this way, the Microsoft C runtime will basically call LoadLibrary() for you automatically when your application starts. Useful, huh?
If the compiler does not produce a .lib alongside your shared library, this basically means that there are no exported symbols in the shared library. This is why CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS solves the problem - it forces all the symbols to be exported anyway, thereby causing the compiler to generate the .lib file detailing these exports. However, as you may be able to work out, this is very much the nuclear option. There's probably a lot of stuff in your shared library that really doesn't need to be visible from the outside! So the pertinent question becomes: why is nothing being exported from my library?
In the linked answer referred to previously, underneath all the CMake technicals, the issue was that the OP was not properly marking their symbols for export. It turns out that this was my issue too, but in a more round-about way: I had decided that for my particular library, which could previously be built in shared or static configurations, I now wanted to force it only to be built in a shared configuration. Because of this, I had removed a particular preprocessor definition from my project in CMake which specified whether the build mode was shared or static; this meant that all of the export annotations on my functions compiled down to nothing (as they should do under a static configuration where they are not needed). The upshot was that I accidentally ended up building the shared library with no exported symbols whatsoever, and MSVC just said "Well I guess there's no point building a .lib then", and didn't produce one. This caused the build issues stating that the .lib could not be found on disk.
When I encountered the answer above, I was suspicious as I wondered why I'd not had to set this value before, despite having used CMake to build Windows shared library projects for years. The correct solution in my case was not to switch CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS on - it was actually to remove the C++ preprocessor condition that checked for my "this is a shared build" preprocessor definition. This re-enabled all of the export annotations on my functions, and everything built as it should.
Before you use CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS, do check that there isn't some subtle bug in your scripts that is preventing your symbols from being exported!

Library's CMake generates DLL. Application's CMake wants LIB

My library has minimal, straightforward CMake code with the pertinent lines
add_library(MyLib <sources>)
install(
TARGETS MyLib
LIBRARY DESTINATION ${destination}/lib
RUNTIME DESTINATION ${destination}/lib
COMPONENT Libraries)
install(
FILES mylib.h
DESTINATION ${destination}/include
COMPONENT Headers)
When executed under Windows, the system generates mylib.dll in ...\build\Release, and mylib.lib and mylib.exp (what's that?) in ...\build\lib\Release. It only installs mylib.dll.
My application has minimal, straightforward CMake code to search for my library:
find_path(MyLib_INCLUDE_DIR mylib.h)
find_library(MyLib_LIBRARIES NAMES MyLib)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(MyLib DEFAULT_MSG MyLib_LIBRARIES MyLib_INCLUDE_DIR)
Which works under Linux, but under Windows results in
-- Could NOT find MyLib (missing: MyLib_LIBRARIES)
From experimentation I know that this error occurs whenever there is only a .DLL file, and no associated .LIB import library.
Shall I correct MyLib to install mylib.lib? How?
Or is it possible to modify my application so that it is satisfied with mylib.dll only? How?
Research done so far
This is not about static vs dynamic linking (DLL and LIB files - what and why?, cmake link against dll/lib): I want dynamic linking; if a .LIB file is required, it has nothing to do with static linking.
This link cmake : shared library : how to get the .lib name instead of .dll name? may be pertinent, but is not explicit enough. Two other questions CMake generated VS project expecting lib instead of dll, Linking dll/lib to a cmake project seem related, but have no answer.
Command install classifies .lib file for a shared library as ARCHIVE. This is explicitly stated in the documentation:
For DLL platforms (all Windows-based systems including Cygwin), the DLL import library is treated as an ARCHIVE target.
So you need to add ARCHIVE clause to install() for install .lib file as well:
install(
TARGETS MyLib
ARCHIVE DESTINATION ${destination}/lib
LIBRARY DESTINATION ${destination}/lib
RUNTIME DESTINATION ${destination}/bin
COMPONENT Libraries)
Not also, that RUNTIME DESTINATION is usually specified as bin, the same as destination for executables. This helps the executables on Windows to locate the shared libraries (.dll).

compiling SFML with cmake and mingw under windows

When i try to run cmake to build a project where i include the SFML library i get the following Error: SFML found but version too low (requested: 2.4, found: 1.x.x)
I downloaded only the source of the newest Version of the library (SFML-2.4.2). I than run cmake (with MinGW Makefiles) And build the binaries into the same folder.
I copied the FindSFML into an subfolder of my project.
After that i had the following folder structure
SFML-2.4.2\
cmake\
Modules\
FindSFML.cmake
CMakeFiles
doc
...
include
lib
src
..
sfml-games\
tetris\
cmake_modules\
FindSFML.cmake
CMakeLists.txt
main.cpp
tetris-build
...
My CMakeLists.txt contains the following stuff:
project(Tetris)
cmake_minimum_required(VERSION 2.8)
aux_source_directory(. SRC_LIST)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake_modules")
Find_package(SFML 2 REQUIRED system window graphics network audio)
include_directories(${SFML_INCLUDE_DIR})
add_executable(${PROJECT_NAME} ${SRC_LIST})
target_link_libraries(${PROJECT_NAME} ${SFML_LIBRARY})
I found that in cmake the entry CMAKE_INSTALL_PREFIX (which i dont get) is set to C:\Program Files (x86)\SFML so i put the library and the lib of SFML into C:\Program Files (x86)\SFML. (what is that CMAKE_INSTALL_PREFIX and should i realy always copy the library and lib folders into my C:\Program Files (x86)\ ??). Now my cmake runs through but when i try to compile the code i get a lot of undifined references to '_imp__....'
By the way on linux i just installed SFML via sudo apt-get install libsfml-dev and it works out of the box.
You're confusing things. CMAKE_INSTALL_PREFIX is the default location where to put SFML when you build the install target (i.e. running make install). This has nothing to do with your other issues.
You don't have to install SFML (or any other library) somewhere under C:\Program Files. That's completely up to you.
What I found to be rather neat is installing MinGW to C:\usr (or creating a symlink to your installation folder) and also use that path for CMAKE_INSTALL_PREFIX when building SFML.
This way MinGW should behave pretty much the way you're used to from Linux (i.e. not having to specify paths for include dir or libraries etc.).
As for your undefined reference errors, you should create a new question only asking for these (and then include at least a few of them), as they have nothing to do with the installation directory.
Right now I can only guess, but it's most likely due to you using the wrong CMake variables for the linker. You won't notice this on Linux, since SFML will be in the default search path (which will also happen if you use C:\usr as described above).
To try fixing this, use this line:
target_link_libraries(${PROJECT_NAME} ${SFML_LIBRARIES} ${SFML_DEPENDENCIES})

Add libraries Qt and LuaJIT / Lua51 with CMake

I am trying to use CMake with Qt and LuaJIT that will run on Visual Studio 2012. I managed somehow to run Qt, but i don't know how to add LuaJIT library to project. I am using source of LuaJIT cloned from http://luajit.org/git/luajit-2.0.git, which is build by running .bat file.
I dont care that LuaJIT will be build by CMake, i just need to link library and add headers to project.
I removed lib folder from my project... Is not worth troubles to have dependancies coupled with project whitout cmake file :D
My project hierarchy is:
+lib
-luajit-2.0
+src
-my sources
+ui
-ui files
-CMakeLists.txt
And CMakeLists.txt file looks like this:
cmake_minimum_required(VERSION 2.8.12)
set(PROJECT "Grapedit")
project(${PROJECT})
# Qt Stuff
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Widgets REQUIRED)
set(SOURCE_FILES
src/main.cpp
src/mainwindow.h
src/mainwindow.cpp
)
set(UI_FILES
ui/mainwindow.ui
)
source_group("UI Files" FILES ${UI_FILES})
qt5_wrap_ui(UI_HEADERS ${UI_FILES})
source_group("Generated UI Headers" FILES ${UI_HEADERS})
add_executable(${PROJECT} ${SOURCE_FILES} ${UI_HEADERS} ${UI_FILES})
qt5_use_modules(${PROJECT} Widgets)
My solution
So it is finally working and I made couple of newbie mistakes... :)
I will write them down for others:
didn't know what is find module... This will search environment and set up locations of libraries or flag that it didn't find them. Since LuaJIT is compatible with Lua51 you can use find_package(Lua51).
Your libraries must be some way visible to CMake. On Windows simplest way is to add them to PATH variable. Or you can add path of your libraries to CMake variable CMAKE_PREFIX_PATH. Open find module, for example FindLua51.cmake and you will see how must be your library organized. On windows I've must installed LuaJIT manualy - created LuaJIT folder and I've put *.h files to include subfolder, *.dll to bin subfolder and *.lib to lib subfolder. Then add bin folder to PATH and set LUA_DIR to LuaJIT folder.
use include_directories on include folder
then you must link libraries target_link_libraries, but after add_executable!
My CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8.12)
# Declare project variables...
set (PROJECT "Grapedit")
set (
SOURCE_FILES
src/main.cpp
src/mainwindow.h
src/mainwindow.cpp
)
set(UI_FILES
ui/mainwindow.ui
)
# Set project name
project(${PROJECT})
# Include Lua directories
include_directories(${LUA_INCLUDE_DIR})
# Qt Stuff
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
# Find packages...
# Will find also LuaJIT, but must be named same as Lua51 and installed into directories
find_package(Lua51)
# Find Qt modules, every module separately
find_package(Qt5Widgets REQUIRED)
# Create nice groups in IDEs
source_group("UI Files" FILES ${UI_FILES})
source_group("Generated UI Headers" FILES ${UI_HEADERS})
# Use Qt UI files
qt5_wrap_ui(UI_HEADERS ${UI_FILES})
# Create executable
add_executable (
${PROJECT}
${SOURCE_FILES}
${UI_HEADERS}
${UI_FILES}
)
# Link libraries...
# Must be after executable is created!
# Link Qt modules
qt5_use_modules (
${PROJECT}
Widgets
)
# Link Lua
target_link_libraries(${PROJECT} ${LUA_LIBRARIES})
# Will not show new windows prompt when running program
if (MSVC)
set_target_properties(${PROJECT} PROPERTIES
WIN32_EXECUTABLE YES
LINK_FLAGS "/ENTRY:mainCRTStartup"
)
endif ()
You are missing the actual linkage which you can amend with the following statement:
target_link_libraries(${PROJECT} luajit-5.1)
For sure, it would be even better if this lua jit could have a cmake find module, or config/version file depending on its exact build system.
You could grab the find module from here:
https://github.com/brimworks/lua-zlib/blob/master/cmake/Modules/FindLuaJIT.cmake
Then you could link against it as follows:
target_link_libraries(${PROJECT} ${LUA_LIBRARIES})
You can see that it would become more dynamic this way rather than hard-coding the exact name. The details for figuring out that would be left with the find module.
Note that you would probably need to use the corresponding variables for the header inclusion then as follows:
include_directories(${LUA_INCLUDE_DIR})
This will take care of automatically finding the include directory, respectively, without you hard-coding it.
You would also need to add the following line into your CMakeLists.txt:
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
and you need to place the downloaded find module into a "cmake" subfolder.
Please refer to the following page for further details about this topic in general:
CMake:How To Find Libraries

CMake: wrong zlib found - how to build zlib from src (with main project CMakeLists.txt) and link it?

// brief version
How can I make CMake to use my supplied zlib (which it also has to build from source) instead of the one found by the finder without breaking the finder for other libs (OpenGL)?
ZLib needs to be used by the main project and also libPNG which comes as source as well.
Primary target platform is Windows.
// longer version:
In my project I need to link against libpng, zlib and OpenGL. With libpng being dependent on zlib. But zlib is also required by the main project.
I need to supply sourcecode for all libs except OpenGL, and build those libraries along with
the main project to assert linking the correct version and simplify building on Windows.
I found ways to do all this with custom libraries where no built-in finder exists, but I can't override the finder properly for just zlib. If I change the search path for libs, then OpenGL is not found.
However I can't get cmake to use my supplied zlib instead of a rouge zlib.DLL that the package finder finds somewhere in my system. (The one from tortoise git)
I tried to set ZLIB_LIBRARY to a specific filepath, but that only works on MinGW, and I also think this is not the way to do it.
(And also I had to explicitly link to png16_static instead of just libpng, for an inexplicable reason.)
Any help on this is much appreciated. Maybe I'm taking this on the wrong way?
Target&Development Platform:
Windows7
Visual Studio 2010
and MinGW (both need to work)
My (simplified example) CMakeLists.txt:
cmake_minimum_required (VERSION 2.6)
project (MyProject)
find_package(OpenGL)
add_executable(MyProject main.cpp)
include_directories(${INCLUDE_DIRECTORIES} "${PROJECT_BINARY_DIR}")
include_directories(${INCLUDE_DIRECTORIES} "external_libs/lpng162")
include_directories(${INCLUDE_DIRECTORIES} "external_libs/zlib-1.2.8")
include_directories(${INCLUDE_DIRECTORIES} "${PROJECT_BINARY_DIR}/external_libs/zlib-1.2.8")
add_subdirectory("external_libs/zlib-1.2.8")
link_directories(${LINK_DIRECTORIES} "${PROJECT_BINARY_DIR}/external_libs/zlib-1.2.8")
# libpng will not build correctly if this not set
set (ZLIB_ROOT "${PROJECT_SOURCE_DIR}/external_libs/zlib-1.2.8")
# manually set this to prevent cmake from finding the tortiose-git zlib.dll first
# DOES NOT WORK CORRECTLY, only with mingw32
set (ZLIB_LIBRARY "${PROJECT_BINARY_DIR}/external_libs/zlib-1.2.8/libzlib.dll")
add_subdirectory("external_libs/lpng162")
TARGET_LINK_LIBRARIES(MyProject png16_static zlib ${OPENGL_LIBRARY})
Project (simplified example) structure:
./main.cpp
./CMakeLists.txt
./external_libs/zlib-1.2.8/ <- contains respective source
./external_libs/lpng162/ <- contains respective source
Third-party libraries most likely call FindZLIB.cmake to determine the location of CMake. You already had the right idea by setting the ZLIB_LIBRARY manually, but were not quite getting it right:
add_subdirectory(<path_to_zlib_src_dir>)
set(ZLIB_INCLUDE_DIR "<path_to_zlib_src_dir>" "${CMAKE_BINARY_DIR}/<path_to_zlib_build_dir>")
set(ZLIB_LIBRARY zlib)
add_subdirectory(<path_to_lpng_src_dir>)
The include directory needs to contain both src and build path as zconf.h is build by CMake
The library name is only the CMake-target name, not the complete path to the resulting file.
On Windows dlls are not automatically copied by CMake. You might want to add some additional code to make sure that the zlib and lpng dlls end up in the right place.
You can call find_package(zlib) yourself to make sure it behaves as expected
In the rare case that a third-party lib does not use the find script, you will have to dig into that project's CMakeLists to find out what is going on

Resources