I have to download zlib to use in my project.
I use externlproject_add() to downaload all zlib repository, build and install it.
After it, I want do install a lib that is part of zlib repository: minizip.
How to set this dependency on cmake?
zlib module:
cmake_minimum_required ( VERSION 2.8.7 )
include (ExternalProject)
if(UNIX)
# An external project for zlib
SET (GIT_URL https://github.com/madler/zlib.git)
SET (ZLIB_INSTALL ${CMAKE_CURRENT_BINARY_DIR})
SET (ZLIB_INCLUDE ${CMAKE_BINARY_DIR}/include/zlib)
SET (ZLIB_STATIC ${CMAKE_BINARY_DIR}/lib/libz.a )
SET (MINIZIP_DIR ${CMAKE_CURRENT_BINARY_DIR}/ZLIB/src/ZLIB/contrib/minizip)
ExternalProject_Add(zlib
PREFIX zlib
GIT_REPOSITORY ${GIT_URL}
INSTALL_DIR ${ZLIB_INSTALL}
PATCH_COMMAND ${CMAKE_COMMAND} -E remove <SOURCE_DIR>/zconf.h
BUILD_IN_SOURCE 1
PATCH_COMMAND ""
CONFIGURE_COMMAND <SOURCE_DIR>/configure --prefix=<INSTALL_DIR> --includedir=${ZLIB_INCLUDE}
)
find_package(ZLIB REQUIRED)
if(ZLIB_FOUND)
add_subdirectory (${MINIZIP_DIR})
endif(ZLIB_FOUND)
SET (ZLIB_INCLUDE_DIR ${ZLIB_INSTALL}/include/zlib)
SET (ZLIB_LIBRARY "${ZLIB_INSTALL}")
ADD_LIBRARY (ZLIB_LIB STATIC IMPORTED DEPENDS zlib)
SET_TARGET_PROPERTIES (ZLIB_LIB PROPERTIES IMPORTED_LOCATION "${ZLIB_STATIC}")
endif(UNIX)
With this zlib module I have an error that following directory
/home/lais/Imagens/agent/build/ZLIB/src/ZLIB/contrib/minizip
doesn't exist yet when I run
cmake ..
And it's true. Doesn't exist yet. I should tell cmake it. But I don't know how to do it.
I solved it download a zip file that have minizip.
cmake_minimum_required ( VERSION 2.8.7 )
include (ExternalProject)
project (zlib)
if(UNIX)
# An external project for zlib
SET (URL http://www.winimage.com/zLibDll/unzip101e.zip)
SET (MINIZIP_INSTALL ${CMAKE_CURRENT_BINARY_DIR})
SET (MINIZIP_STATIC ${CMAKE_BINARY_DIR}/lib/minizip.a )
message ("zlib = ${zlib}")
ExternalProject_Add(minizip
DEPENDS zlib
PREFIX minizip
URL ${URL}
INSTALL_DIR ${MINIZIP_INSTALL}
BUILD_IN_SOURCE make
CONFIGURE_COMMAND ""
)
SET (MINIZIP_LIBRARY "${MINIZIP_INSTALL}")
ADD_LIBRARY (MINIZIP_LIB STATIC IMPORTED DEPENDS minizip, zlib)
SET_TARGET_PROPERTIES (MINIZIP_LIB PROPERTIES IMPORTED_LOCATION "${MINIZIP_STATIC}")
endif(UNIX)
Related
I tried to used https://github.com/julianxhokaxhiu/SteamworksSDKCI to use steam api on a simple SFML application (helloworld).
I wanted to use cmake to learn it, but I am struggling to understand how the provided CMakeLists and Find*.cmake file are expected to be used.
Currently, I have modified the CMakeLists to change the INSTALL_DIR
INSTALL_DIR "${CMAKE_BINARY_DIR}/../../vendor"
and my CMakeLists is :
cmake_minimum_required(VERSION 3.19)
project(SfmlWithCMake VERSION 1.0)
include(FetchContent)
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake_steam")
# Configure external project
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/cmake_steam)
execute_process(
COMMAND ${CMAKE_COMMAND} ${CMAKE_SOURCE_DIR}/cmake_steam
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/cmake_steam
)
# Build external project
execute_process(
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR}/cmake_steam
)
set(BUILD_SHARED_LIBS OFF)
FetchContent_Declare(
SFML
GIT_REPOSITORY https://github.com/SFML/SFML.git
GIT_TAG 2.5.1
)
FetchContent_MakeAvailable(SFML)
find_package(STEAMWORKSSDK REQUIRED)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED true)
# Generate config.h
configure_file(config.h.in config.h)
add_executable(
SfmlWithCMake
main.cpp
)
get_target_property(STEAMSDK STEAMWORKSSDK::STEAMWORKSSDK INCLUDE_DIRECTORIES)
target_include_directories(
SfmlWithCMake
PRIVATE
"${PROJECT_BINARY_DIR}"
"${STEAMSDK}"
)
target_link_libraries(
SfmlWithCMake
sfml-graphics
STEAMWORKSSDK::STEAMWORKSSDK
-static gcc stdc++ winpthread -dynamic
)
install(TARGETS SfmlWithCMake DESTINATION bin)
How to get include directories?
I do not succeed to add the steam include to the target_include_directories.
Here the ${STEAMSDK} is my last attempt to get the directory.
If I replace this by ${PROJECT_BINARY_DIR}/vendor/include, everything works.
Also, why does the SFML include are automatically added to my target include directories and not the steam one?
Am I using the Find*.cmake file the right way?
I understood that ExternalProject_Add was performed at build time and thus, as the find_package is needed at configue time, I added the two "execute_process". But, the readme on github only says to do the find package and add the target to target_link_libraries...
Thanks.
I am still at the beginning of my journey regarding ExternalProject. I have two projects used by my main project as dependencies: libpng and zlib. The former depends on the latter.
Inside the official CMakeLists.txt of libpng I see that there is the option PNG_BUILD_ZLIB, which you have to disable if you want to use a custom version of zlib. Currently my two externals look like this:
ExternalProject_Add(zlib
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/deps/zlib
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
DOWNLOAD_DIR ""
TMP_DIR ${DEPS_TMP}/zlib
STAMP_DIR ${DEPS_STAMP}/zlib
LOG_DIR ${DEPS_LOG}/zlib
BINARY_DIR ${DEPS_BUILD}/zlib
SOURCE_DIR ${DEPS}/zlib
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "Skipping install step for dependency zlib"
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}
BUILD_ALWAYS OFF
)
# Set zlib variables required by libpng
ExternalProject_Get_property(zlib BINARY_DIR)
ExternalProject_Get_property(zlib SOURCE_DIR)
set(zlib_DIR "${BINARY_DIR}/Debug" CACHE PATH "zlib dir" FORCE)
set(ZLIB_ROOT ${SOURCE_DIR} CACHE PATH "zlib root" FORCE) # ${zlib_DIR}
set(ZLIB_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "zlib include dir" FORCE)
if(WIN32)
set(ZLIB_LIBRARY ${zlib_DIR}/zlibd.dll CACHE FILEPATH "zlib dynamic library" FORCE)
set(ZLIB_LIBRARIES ${zlib_DIR}/zlibd.dll CACHE FILEPATH "zlib dynamic library" FORCE)
else()
set(ZLIB_LIBRARY ${zlib_DIR}/libzlibd.so CACHE FILEPATH "zlib dynamic library" FORCE)
set(ZLIB_LIBRARIES ${zlib_DIR}/libzlibd.so CACHE FILEPATH "zlib dynamic library" FORCE)
endif()
ExternalProject_Add(libpng
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/deps/png
DEPENDS zlib
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
DOWNLOAD_DIR ""
TMP_DIR ${DEPS_TMP}/png
STAMP_DIR ${DEPS_STAMP}/png
LOG_DIR ${DEPS_LOG}/png
BINARY_DIR ${DEPS_BUILD}/png
SOURCE_DIR ${DEPS}/libpng
INSTALL_COMMAND "${CMAKE_COMMAND}" -E echo "Skipping install step for dependency libpng"
INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX}
BUILD_ALWAYS OFF
CMAKE_ARGS
"-DPNG_BUILD_ZLIB=1" # Use zlib built as a dependency of this project
"-DPNG_SHARED=1"
"-DPNG_STATIC=0"
"-DPNG_TESTS=0"
"-DPNG_EXECUTABLES=0"
"-DPNG_HARDWARE_OPTIMIZATIONS=1"
"-DPNG_DEBUG=0"
)
where
${DEPS} points at a directory where currently every dependency's source code resides and is manually downloaded using git submodules commands
${DEPS_xyz} points at a ExternalProject directory for a specific purpose (logs, stamps, build files, temporary files etc.) and all are placed inside the build directory of the whole project.
The problem I am having is that I am failing at passing the include directory to libpng and this results in the header zlib.h not being found during the build step for that dependency. Apparently
set(ZLIB_INCLUDE_DIRS ${SOURCE_DIR} CACHE PATH "zlib include dir" FORCE)
isn't really passed to the dependency (but in itself it is pointing at the correct path on the filesystem where the header file is included).
Do I have to add the include directory as a CMAKE_ARGS entry or is there some other easier way?
I also checked here but the suggested solution (I just passed the stuff directly into my CMAKE_ARGS)
CMAKE_ARGS
"-DPNG_BUILD_ZLIB=1" # Use zlib built as a dependency of this project
"-DZLIB_INCLUDE_DIRS=\"${${ZLIB_INCLUDE_DIRS}}\"" # Pass the ZLIB_INCLUDE_DIRS to the dependency using the value of the variable set above
"-DPNG_SHARED=1"
"-DPNG_STATIC=0"
"-DPNG_TESTS=0"
"-DPNG_EXECUTABLES=0"
"-DPNG_HARDWARE_OPTIMIZATIONS=1"
"-DPNG_DEBUG=0"
doesn't work.
I want to build a library libpng from source which requires libz which in turn I also want to build from source. I have one CMakeLists.txt file so far and the part that defines the build steps for both libraries looks like this:
if(NOT EXISTS ${CMAKE_BINARY_DIR}/build-zlib/build/libz.a)
file(DOWNLOAD https://www.zlib.net/zlib-1.2.11.tar.gz zlib.tar.gz TLS_VERIFY ON)
file(ARCHIVE_EXTRACT INPUT zlib.tar.gz)
include(ExternalProject)
ExternalProject_Add(zlib
SOURCE_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.11
BINARY_DIR ${CMAKE_BINARY_DIR}/build-zlib/build
INSTALL_COMMAND cmake -E echo "Skipping install"
CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON
)
message(STATUS "zlib will be built during 'make'")
endif()
if(NOT EXISTS ${CMAKE_BINARY_DIR}/build-png/build/libpng.a)
include(ExternalProject)
ExternalProject_Add(png
GIT_REPOSITORY "https://github.com/glennrp/libpng.git"
GIT_TAG "v1.6.37"
BINARY_DIR ${CMAKE_BINARY_DIR}/build-png/build
INSTALL_COMMAND cmake -E echo "Skipping install"
CMAKE_ARGS -DCMAKE_POSITION_INDEPENDENT_CODE=ON
)
message(STATUS "libpng will be built during 'make'")
endif()
There are two problems: First, CMake doesn't know that libz has to be built before libpng. Second, even if libz would be built before, CMake doesn't know that libz will be placed in ${CMAKE_BINARY_DIR}/build-zlib/build. I suppose the second problem may be fixed by adding list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}/build-zlib/build) (please correct me if I'm wrong) but how do I deal with the first problem? Freely I've tried to add add_dependencies(png zlib) but libz is not getting built before libpng. The error message therefore states that libz can't be found:
CMake Error at /snap/cmake/876/share/cmake-3.20/Modules/FindPackageHandleStandardArgs.cmake:230 (message):
Could NOT find ZLIB (missing: ZLIB_LIBRARY ZLIB_INCLUDE_DIR)
Is there a way in cmake to find the source directory of the CMakeLists.txt file in which a target was defined?
Somethign like:
if (TARGET Foo)
message("Library Foo was alread built in ${LOCATION_OF_FOOS_CMAKE}")
else()
add_library(Foo ...)
endif()
Edit:
Unfortunately, my cmake scripts have to work on a default ubuntu 14.04 installation. So I'm limited to cmake 2.8
You can use target property SOURCE_DIR (added with CMake 3.7):
get_target_property(FOO_SOURCE_DIR Foo SOURCE_DIR)
For older versions of CMake you can overwrite e.g. add_library() and define your own SOURCE_DIR target property:
function(add_library _target)
_add_library(${_target} ${ARGN})
set_target_properties(${_target} PROPERTIES SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
endfunction(add_library)
First off, I'm relatively new to cmake. I'm trying to use cmake to build a project with a single external dependency. I specify the INSTALL_DIR for the external project to be CMAKE_INSTALL_PREFIX, so it installs to the same place as the parent project. But when I run make, it ignores it and tries to install to /usr/local/lib.
Here's my CMakeList.txt:
cmake_minimum_required( VERSION 2.8 )
include( ExternalProject )
project( capture )
add_library( capture SHARED capture.cc )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11" )
ExternalProject_Add( proj_exceptions
GIT_REPOSITORY /home/user/workspace/exceptions
INSTALL_DIR ${CMAKE_INSTALL_PREFIX}
)
add_library( exceptions SHARED IMPORTED )
set_property( TARGET exceptions
PROPERTY IMPORTED_LOCATION ${CMAKE_INSTALL_PREFIX}/lib/libexceptions.so
)
add_dependencies( exceptions proj_exceptions )
include_directories( ${CMAKE_INSTALL_PREFIX}/include )
target_link_libraries( capture exceptions )
install( TARGETS capture DESTINATION lib )
install( FILES capture.h DESTINATION include )
CMakeLists.txt for the external project looks like this:
cmake_minimum_required( VERSION 2.8 )
project( exceptions )
add_library( exceptions SHARED exceptions.cc )
install( TARGETS exceptions DESTINATION lib )
install( FILES exceptions.hh DESTINATION include )
It clones and builds the external project just fine, but it chokes on the install step:
Install the project...
-- Install configuration: ""
-- Installing: /usr/local/lib/libexceptions.so
CMake Error at cmake_install.cmake:42 (file):
file INSTALL cannot copy file
"/home/user/workspace/capture/build/proj_exceptions-prefix/src/proj_exceptions-build/libexceptions.so"
to "/usr/local/lib/libexceptions.so".
Makefile:66: recipe for target 'install' failed
As you can see, the install configuration is empty. Looking through the generated config for the external project, I found this in cmake_install.cmake:
if(NOT DEFINED CMAKE_INSTALL_PREFIX)
set(CMAKE_INSTALL_PREFIX "/usr/local")
endif()
So, it seems that passing INSTALL_DIR to ExternalProject_Add doesn't set the install prefix. The install step succeeds, if I instead use:
ExternalProject_Add( proj_exceptions
GIT_REPOSITORY /home/djones/workspace/exceptions
CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}"
)
So what's the purpose of INSTALL_DIR then?
You're right for the purpose of INSTALL_DIR, but you may have missed some steps.
According the cmake 2.8 doc about external project:
Install Step
The INSTALL_DIR is underneath the calling project’s
binary directory. Use INSTALL_DIR to specify a different location.
Note that in addition to setting INSTALL_DIR, you also have to pass
-DCMAKE_INSTALL_PREFIX or --prefix to the CMake or configure command. It is not used automatically in the configure step since not all
projects follow this convention.
# [INSTALL_DIR dir]
You can refer to the install directory in your configure command, for
example:
CONFIGURE_COMMAND SOURCE_DIR/configure --prefix=INSTALL_DIR
# [INSTALL_COMMAND cmd...]
CMake-based projects use ‘cmake--build’ to build the install target.
Other projects use ‘make install’. Use INSTALL_COMMAND to customize
the install step. Use INSTALL_COMMAND “” to omit the install step. The
install command executes with the working directory set to
.
So try to update your cmake command, or use the custom INSTALL_COMMAND feature.