Linking OpenCV with static zlib using IPP, using CMake on Linux - opencv3.0

I'm building OpenCV from source, using the standalone Intel version of the IPP libraries. I'm also using the Intel-optimised version of zlib, which (unlike the standard version of zlib) carries a dependency on three further IPP libraries. Also, I'm linking zlib in statically, so I need to make any target that uses it aware of these dependencies.
I've already got everything working on Windows, and now I'm trying to do the same in Linux. I've added the following text to the master CMakeLists.txt file in Open CV, just after the place where all the other dependencies are searched for and initialised:
include(cmake/OpenCVFindLibsGrfmt.cmake)
include(cmake/OpenCVFindLibsGUI.cmake)
include(cmake/OpenCVFindLibsVideo.cmake)
include(cmake/OpenCVFindLibsPerf.cmake)
include(cmake/OpenCVFindLAPACK.cmake)
include(cmake/OpenCVFindProtobuf.cmake)
#---------------------------My changes start here-------------------------
# We insert this code here because this is the point where ZLIB_LIBRARIES
# has just become defined, and by putting it here we ensure that our
# changes are propagated throughout the rest of the project.
if (MSVC)
add_library(ippdcmt STATIC IMPORTED)
add_library(ippsmt STATIC IMPORTED)
add_library(ippcoremt STATIC IMPORTED)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# We are compiling 64-bit code
set_target_properties(ippdcmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippdcmt.lib")
set_target_properties(ippsmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippsmt.lib")
set_target_properties(ippcoremt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64_win/ippcoremt.lib")
else()
# We are compiling 32-bit code
set_target_properties(ippdcmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ippdcmt.lib")
set_target_properties(ippsmt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ippsmt.lib")
set_target_properties(ippcoremt PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32_win/ipcoremt.lib")
endif()
list(APPEND ZLIB_LIBRARIES ippdcmt ippsmt ippcoremt)
elseif(CMAKE_COMPILER_IS_GNUCC)
add_library(libippdc STATIC IMPORTED)
add_library(libipps STATIC IMPORTED)
add_library(libippcore STATIC IMPORTED)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
# We are compiling 64-bit code
set_target_properties(libippdc PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libippdc.a")
set_target_properties(libipps PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libipps.a")
set_target_properties(libippcore PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/intel64/libippcore.a")
else()
# We are compiling 32-bit code
set_target_properties(libippdc PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libippdc.a")
set_target_properties(libipps PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libipps.a")
set_target_properties(libippcore PROPERTIES IMPORTED_LOCATION "${IPP_ROOT_DIR}/lib/ia32/libippcore.a")
endif()
list(APPEND ZLIB_LIBRARIES libippdc libipps libippcore)
endif()
#---------------------------My changes end here---------------------------
On running CMake and then make, the build gets to 99% after a couple of hours and then fails on one of the vary last modules to be compiled, complaining that it cannot find the IPP-related dependencies for zlib. On inspecting the compile log, it's easy to see why: for some reason, the makefile has put zlib as the very last library on the link line, after the relevant Intel IPP libraries, and since gcc reads the link line in strict order this means that the dependencies aren't handled correctly.
What I need therefore is a way to force CMake to construct the makefile such a way that the IPP libraries are always put after zlib on the link line.
I've read elsewhere on this site that I ought to be able to achieve this using the CMake property IMPORTED_LINK_INTERFACE_LIBRARIES. So I've tried adding a line akin to
set_target_properties([something to denote zlib] PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES libippdc libipps libippcore)
...immediately after list(APPEND ZLIB_LIBRARIES libippdc libipps libippcore). However, I can't figure out what to put in place of [something to denote zlib] so that CMake understands and acts accordingly. If I replace it with ZLIB::ZLIB (the usual output of CMake's native FindZLIB function), then I get no error messages but it doesn't make a blind bit of difference; a couple of hours later the build fails exactly as it did before. If I try replacing [something to denote zlib] with anything else I can think of or find elsewhere in OpenCV's CMake files - so far, 'zlib', 'ZLIB', 'ZLIB_LIBRARY', 'zlib.a', 'libz.a' - then CMake fails with an error message saying:
set_target_properties Can not find target to add properties to: libz.a (or whatever)
So I guess my question is, how does OpenCV's CMake system refer internally to zlib, so that I can add this property to it? Alternatively, am I approaching this in completely the wrong way, and is there a better way to achieve my objective (which is, in short, having an OpenCV build that statically links the Intel-enhanced version of zlib with all its dependencies)?

It turned out that there was nothing wrong with my block of code. I'm not sure if the set_target_properties line was even necessary, though to be on the safe side I left it in with the final syntax:
set_property(TARGET ZLIB::ZLIB
PROPERTY INTERFACE_LINK_LIBRARIES libippdc libipps libippcore)
The main problem was the location of my block of code. It turned out that, within the call to include(cmake/OpenCVFindLibsGrfmt.cmake), zlib itself was found and initialised along with libtiff, libpng and libIlmImf, all of which depended on it. Therefore, the properties of these targets contained a dependency on zlib alone, and my block of code which came afterwards did not change this. My block of code had to be moved between the initialisation of zlib and the initialisation of everything that depended upon it.
This was a bit tricky, but in the end what I did was:
Moved the line include(cmake/OpenCVFindLibsPerf.cmake) to first in the block, so that the IPP library was found and IPP_ROOT_DIR properly initialised.
Extracted the first ten lines or so from cmake/OpenCVFindLibsGrfmt.cmake, where zlib is initialised, and placed them into the main CMakeLists.txt fine immediately after include(cmake/OpenCVFindLibsPerf.cmake).
Then I re-inserted my block of custom code.
Finally I put in the rest of the includes, to complete initialisation of all the other libraries.
The result finally, was a clean build.

Related

cmake: using shared library while building when only headers exist

I would like to
build a binary that is relying on a shared library at runtime.
the library does not exist while compiling the binary.
the headers for the library are available
I would like to create a CMake project under those circumstances. Therefore I tried the following, but it will complain about the missing lib for sure:
cmake_minimum_required (VERSION 3.8)
project (example)
add_executable(${PROJECT_NAME}
main.c
)
target_link_libraries(${PROJECT_NAME}
PRIVATE
# system libs
lib_that_does_not_yet_exist
)
When removing the link instruction to lib_that_does_not_yet_exist, then I will get a undefined reference error.
Question: Is there any way to accomplish what I need?
Background: I am crosscompiling the binary, the lib is therefore having the wrong architecture to install it on the host. I know there may be some ways around that issue, but I am mainly interested in the above question.

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!

Add compile option if shared lib is linked

I have a special compiler that need an extra flag -non-static when linking an executable to with an shared lib:
gcc main.cpp -non-static -lshared -o main
(Note: Its the compiler for vxworks)
How can i do this in CMake?
Solutions i have used so far (but are not satisfying):
Always set -non-static in the toolchain file. Works, but has unwanted side effects when you dont need any shared lib.
set(CMAKE_EXE_LINKER_FLAGS ${CMAKE_EXE_LINKER_FLAGS} "-non-static")
Create a INTERFACE library with -non-static compile option set. However, each new project must rewrite this and and each executable must link this library (if it links any shared lib):
add_library(allwaysLinkMe INTERFACE)
if(CMAKE_SYSTEM_NAME STREQUALS "VxWorks")
target_link_libraries(allwaysLinkMe INTERFACE "-non-static")
endif()
add_library(shared SHARED a.cpp)
add_executatble(main main.cpp)
target_link_libraries(main shared allwaysLinkMe)
Or i link this library to all other shared libraries:
add_library(shared SHARED a.cpp)
target_link_libraries(shared allwaysLinkMe)
add_executatble(main main.cpp)
target_link_libraries(main shared)
In both cases, I must use ifs to prevent this from failing with other target platforms. Also both are pretty ugly and error prone.
I am looking for a solution, that is only in the toolchain/platform/compiler file(s) and no change to the project must be made.

Linking SFML within CMake, compiling from sources

I'm trying to include SFML as a dependency in my CMake project, and it compiles SFML fine, but I can't figure out how to link it.
Here's my CMakeLists.txt, with annotated comments:
cmake_minimum_required(VERSION 3.9.1)
set(CMAKE_LEGACY_CYGWIN_WIN32 1)
set (CMAKE_CXX_STANDARD 11) # Set C++11
project(CHIP8)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # static library
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # dynamic library
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # executables
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/modules" ${CMAKE_MODULE_PATH})
# Include SFML
add_subdirectory(${CMAKE_SOURCE_DIR}/dep/SFML)
include_directories(${CMAKE_SOURCE_DIR}/dep/SFML/include)
#Include where to find headers
include_directories(./src)
include_directories(./src/headers)
# Do a GLOB search, and add them to executable
set(EXECUTABLE_NAME "CHIP8")
file(GLOB SRC_FILES
"src/headers/*.h"
"src/*.cpp"
)
add_executable(${EXECUTABLE_NAME} ${SRC_FILES})
target_link_libraries(${EXECUTABLE_NAME} SFML) #Here is where the problem lies!
As you can see, I'm adding the subdirectory ./dep/SFML so it compiles with its own CMakeLists. Including the headers too on the next line, which VSCode picks up.
However, I'm having trouble on the last line: target_link_libraries. It can't find sfml SFML or SFML2. Therefore, I'm not sure how to link it.
Anyone have any idea?
Thanks.
SFML is not a single library, but a set of libraries, each of which corresponds to some component. For component named
<component-name>
the library target is named
sfml-<component-name>
When use SFML in your code, you should know which SFML component(s) you use (see SFML docs/tutorials), and link with corresponded libraries:
# Assuming you use "graphics" and "system" SFML components
target_link_libraries(<your-executable> sfml-graphics sfml-system)
Note, that such targets' naming is not officially documented, so it can be changed in the future.
Preferred way for link with SFML is to install it before (or during) configuring your project, and use
find_package(SFML REQUIRED COMPONENTS graphics system)
include_directories(${SFML_INCLUDE_DIR})
target_link_libraries(<your-executable> ${SFML_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