I have a relatively big CMake project with a lot of subfolders and files. I want to run a custom command after any binary is created when building this project. I've been testing with Hello World and I know I'll need something like this:
EDIT: I've updated the question to reflect my current progress.
# Get list of all files and folders in current dir recursively
set(SUBFDIRS)
file(GLOB_RECURSE ALLFILES LIST_DIRECTORIES true "*" "*")
foreach(SUBFILE ${ALLFILES})
IF(IS_DIRECTORY ${SUBFILE} AND NOT ${SUBFILE} MATCHES ".*CMakeFiles.*")
message("Adding directory: ${SUBFILE}")
LIST(APPEND SUBDIRS ${SUBFILE})
ENDIF()
endforeach()
# Also add current directory to directory list
LIST(APPEND SUBDIRS .)
LIST(REMOVE_DUPLICATES SUBDIRS)
message("-- Detected subdirectories: ${SUBDIRS}")
# Loop over all subdirectories
foreach(subdir ${SUBDIRS})
# Get a list of all targets
get_property(BUILDSYSTEM_TARGETS DIRECTORY ${subdir} PROPERTY BUILDSYSTEM_TARGETS)
# For each target, add a custom target that will run a custom command
foreach(TARGET_DEFINED ${BUILDSYSTEM_TARGETS})
get_target_property(target_type ${TARGET_DEFINED} TYPE)
if (target_type STREQUAL "EXECUTABLE")
message("-- Adding custom target for executable ${TARGET_DEFINED}...")
add_custom_target(custom_${TARGET_DEFINED} ALL)
add_custom_command(TARGET custom_${TARGET_DEFINED}
POST_BUILD
COMMAND my_custom_command $<TARGET_FILE:${TARGET_DEFINED}> $<TARGET_FILE:${TARGET_DEFINED}>
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS $<TARGET_FILE:${TARGET_DEFINED}>
)
else()
message("-- Target ${TARGET_DEFINED} is not an executable. Ignoring!")
endif()
endforeach()
endforeach()
This seems to work the way I want it to, except for the fact that it generates CMake errors like this one when trying to get a list of targets for a directory:
CMake Error at CMakeLists.txt:34 (get_property):
get_property DIRECTORY scope provided but requested directory was not
found. This could be because the directory argument was invalid or, it is
valid but has not been processed yet.
Related
I am trying to create a CMake file for my project which uses NetCDF. I am very new at CMake (this is my first try), so I apologize if some of this stuff is evident.
To install NetCDF I followed the steps in the git guide shown here
I believe I did the steps correctly. I am trying to use the NetCDF C++ library, but I also had to install the C library for compilation purposes. I did this by using:
sudo apt install libnetcdf-dev
When I run the following command, I receive appropriate output (according to the git guide):
nc-config --has-nc4
So far so good... I hope. Here is my CMakeLists.Txt:
cmake_minimum_required(VERSION 3.16)
project(orbit LANGUAGES CXX)
# ##############################################################################
# Conan Packages
# ##############################################################################
set(CONAN_EXTRA_REQUIRES "") set(CONAN_EXTRA_OPTIONS "")
list(APPEND CONAN_EXTRA_REQUIRES boost/1.73.0) list(APPEND CONAN_EXTRA_REQUIRES eigen/3.3.7)
if(BUILD_SHARED_LIBS) list(APPEND CONAN_EXTRA_OPTIONS "Pkg:shared=True") endif()
include(cmake/Conan.cmake) run_conan()
# ##############################################################################
find_file(CMAKE_PREFIX_PATH netCDFCxxConfig.cmake)
find_package (NetCDF REQUIRED) include_directories(${NETCDF_INCLUDES})
# set(SOURCE test.cpp player.cpp player.hpp)
# include_directories(include)
# Search all .cpp files
file(GLOB_RECURSE SOURCE_FILES "*.cpp")
add_executable(test ${SOURCE_FILES})
target_link_libraries(test
PRIVATE
CONAN_PKG::boost
CONAN_PKG::eigen
${NETCDF_LIBRARIES_CXX})
And here is the error output:
CMake Error at CMakeLists.txt:24 (find_package):
By not providing "FindNetCDF.cmake" in CMAKE_MODULE_PATH this project has
asked CMake to find a package configuration file provided by "NetCDF", but
CMake did not find one.
Could not find a package configuration file provided by "NetCDF" with any
of the following names:
NetCDFConfig.cmake
netcdf-config.cmake
Add the installation prefix of "NetCDF" to CMAKE_PREFIX_PATH or set
"NetCDF_DIR" to a directory containing one of the above files. If "NetCDF"
provides a separate development package or SDK, be sure it has been
installed.
My understanding is that this error comes from me not doing the following line from the git guide correctly:
Make sure that either nc-config is in your PATH, or that the location of netCDFConfig.cmake is in CMAKE_PREFIX_PATH.
I have tried adding the nc-config to my PATH, by running:
export PATH="nc-config:$PATH"
But this does not resolve the issue...
Additionally, I have tried to find a netCDFConfig.cmake file in my computer, however it does not seem to exist. I do have a netCDFCxxConfig.cmake, but I am not sure if this is the same, or how I could go about using it here.
Does anyone have any experience with this issue, and know how to resolve it? Any help would be greatly appreciated, and I do apologize if such a solution has been provided in the past.
Edit:
I was able to get CMake to finally find the file, but now it gets lost looking for another one... Here is the file it was not finding in my original post:
# NetCDF CXX Configuration Summary
####### Expanded from #PACKAGE_INIT# by configure_package_config_file() #######
####### Any changes to this file will be overwritten by the next CMake run ####
####### The input file was netCDFCxxConfig.cmake.in ########
get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE)
macro(set_and_check _var _file)
set(${_var} "${_file}")
if(NOT EXISTS "${_file}")
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
endif()
endmacro()
macro(check_required_components _NAME)
foreach(comp ${${_NAME}_FIND_COMPONENTS})
if(NOT ${_NAME}_${comp}_FOUND)
if(${_NAME}_FIND_REQUIRED_${comp})
set(${_NAME}_FOUND FALSE)
endif()
endif()
endforeach()
endmacro()
####################################################################################
include(CMakeFindDependencyMacro)
if (1)
if(EXISTS "")
set(netCDF_ROOT "")
endif()
if(EXISTS "/usr/lib/x86_64-linux-gnu/cmake/netCDF")
set(netCDF_DIR "/usr/lib/x86_64-linux-gnu/cmake/netCDF")
endif()
find_dependency(netCDF)
set(NETCDF_C_LIBRARY ${netCDF_LIBRARIES})
set(NETCDF_C_INCLUDE_DIR ${netCDF_INCLUDE_DIR})
else()
set(NETCDF_C_LIBRARY "netcdf")
set(NETCDF_C_INCLUDE_DIR "/usr/include")
endif()
if (NOT TARGET netCDF::netcdf)
add_library(netCDF::netcdf UNKNOWN IMPORTED)
set_target_properties(netCDF::netcdf PROPERTIES
IMPORTED_LOCATION "${NETCDF_C_LIBRARY}"
INTERFACE_INCLUDE_DIRECTORIES "${NETCDF_C_INCLUDE_DIR}"
)
endif()
include("${CMAKE_CURRENT_LIST_DIR}/netcdf-cxx4Targets.cmake")
This last line is where it all sort of goes wrong. Here is where it has issues finding the netcdf-cxx4Targets.cmake.
The file I have just posted is in the directory: netcd-cxx4/build
netcdf-cxx4Targets.cmake is in the directory:
netcd-cxx4/build/CMakeFiles/Export/lib/cmake/netCDF
So the first should be able to find the other?
The netCDFCxxConfig.cmake file is what you want to use. From quickly looking at the GitHub repository, there is a template for this file (netCDFCxxConfig.cmake.in), but not one for netCDFConfig.cmake.in. Therefore, my conclusion is the maintainers probably changed the config file name at some point, and forgot to update their README documentation to netCDFCxxConfig.cmake.
You can add the location of the netCDFCxxConfig.cmake file to the CMAKE_PREFIX_PATH list variable in your CMake file. Then, link to the imported target netCDF::netcdf defined in the netCDFCxxConfig.cmake file.
...
# ##############################################################################
# Don't do this.
find_file(CMAKE_PREFIX_PATH netCDFCxxConfig.cmake)
# Instead, append the path to the config file using the 'list' command.
list(APPEND CMAKE_PREFIX_PATH "/path/to/installed/netcdf")
# Look for the 'netCDFCxx' package, since that is what the config file is called.
find_package (netCDFCxx REQUIRED)
# Probably don't need this if we use the imported target below.
include_directories(${NETCDF_INCLUDES})
# set(SOURCE test.cpp player.cpp player.hpp)
# include_directories(include)
# Search all .cpp files
file(GLOB_RECURSE SOURCE_FILES "*.cpp")
add_executable(test ${SOURCE_FILES})
# Link to the imported target 'netCDF::netcdf' here instead.
target_link_libraries(test
PRIVATE
CONAN_PKG::boost
CONAN_PKG::eigen
netCDF::netcdf)
I am writing a game engine and I have a directory called thirdparty where all external libraries my engine uses are placed:
thirdparty/...
/zlib
/freetype2
/SDL2
/...
So, the engine directory structure looks like:
engine/actors
engine/memory_allocator
engine/renderer
engine/...
engine/thirdparty
engine/thirdparty/CMakeLists.txt
engine/CMakeLists.txt
The engine/CMakeLists.txt:
cmake_minimum_required (VERSION 3.2)
project(Engine)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fvisibility=hidden -fvisibility-inlines-hidden -Wall -Werror")
# Include build directory to be able to include generated files:
set(CMAKE_INCLUDE_CURRENT_DIR ON)
file(GLOB GLAD_SOURCES thirdparty/glad/src/glad.c)
file(GLOB ACTOR_SOURCES actors/*.cpp)
file(GLOB LOGIC_SOURCES logic/*.cpp)
file(GLOB UI_SOURCES ui/*.cpp)
set(SOURCES ${GLAD_SOURCES}
${ACTOR_SOURCES}
${LOGIC_SOURCES}
${UI_SOURCES})
add_library(engine SHARED ${SOURCES})
include_directories(thirdparty/glm/)
include_directories(thirdparty/glad/include)
include_directories(thirdparty/tinyxml2/)
include_directories(thirdparty/zlib/)
include_directories(thirdparty/sdl2/SDL2-2.0.5/)
include_directories(./)
add_subdirectory(../../thirdparty thirdparty)
target_link_libraries(engine SDL2)
target_link_libraries(engine tinyxml2)
target_link_libraries(engine zlib)
The engine/thirdparty/CMakeLists.txt:
set(BUILD_CPU_DEMOS OFF CACHE BOOL "" FORCE)
set(BUILD_DEMOS OFF CACHE BOOL "" FORCE)
set(BUILD_EXTRAS OFF CACHE BOOL "" FORCE)
set(BUILD_BULLET2_DEMOS OFF CACHE BOOL "" FORCE)
set(BUILD_UNIT_TESTS OFF CACHE BOOL "" FORCE)
set(FREETYPE_NO_DIST OFF CACHE BOOL "" FORCE)
set(OLD_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "")
# add_subdirectory(bullet3)
set(CMAKE_CXX_FLAGS "${OLD_CXX_FLAGS}")
add_subdirectory(freetype2)
set(BUILD_TESTING OFF CACHE BOOL "" FORCE)
add_subdirectory(tinyxml2)
add_subdirectory(sdl2/SDL2-2.0.5/)
add_subdirectory(zlib)
So, the main engine CMakeLists.txt is in the root directory of the engine's sources and there is another CMakeLists.txt for building third-party libraries in the thirdparty subdirectory of engine's root directory.
The problem is that some of subdirectories in the thirdparty, for example, SDL2 and zlib contain the same target names, added via add_custom_target and so CMake fails to generate the Makefile because of this naming conflicts:
zlib's CMakeLists.txt (in the end):
# uninstall target
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()
SDL2's CMakeLists.txt:
##### Uninstall target #####
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)
So the final error is:
CMake Error at /home/user/engine/thirdparty/sdl2/SDL2-2.0.5/CMakeLists.txt:1624 (add_custom_target):
add_custom_target cannot create target "uninstall" because another target
with the same name already exists. The existing target is a custom target
created in source directory
"/home/user/engine/thirdparty/zlib". See
documentation for policy CMP0002 for more details.
Is there any way to fix this? Perhaps, there is a way to rename these targets by adding any prefix to it so they will never conflict?
It mostly depends on which generators you are targeting. A solution that imposes limitations on them is using ALLOW_DUPLICATE_CUSTOM_TARGETS.
As from the documentation:
Allow duplicate custom targets to be created.
It works only for Makefile generators anyway:
For projects that care only about Makefile generators and do not wish to support Xcode or VS IDE generators, one may set this property to true to allow duplicate custom targets.
Otherwise consider to not pack dependencies with the project directly and use the other tools around (like Find*) to get them along with the right paths on the target systems.
How Can I link to external library that I have packed with my project?
Here is how my project is set up:
I have a folder called App and that is where my main.cpp sits.
C:\Raph\src\App
main.cpp
I also have a folder called "ExternalLibrary" and that is where I have bundled Qt Library that I need to use in my project:
C:\Raph\src\ExternalLibrary\Platform\Windows\Qt5.6\VS2013_64bit
It contains 3 folders:
**bin**
moc.exe
rcc.exe
uic.exe
......
bunch of Qt dll files
**include**
bunch of Qt header files
**lib**
bunch of Qt lib files
I need to setup Cmake to do three things:
Link to Qt library that I have packed in "ExternalLibrary" dynamically.
Automatically performs moc.exe, uic.exe, rcc.exe every time I add a Qt class or a resource in the project. I also dont need any of
the generated moc_myClassname.cpp to show up in the project.
I want All the Qt dlls to end up in my bin folder where the executable sits. e.g:
C:\Raph\build\Raph\Windows\x64\Debug\bin
Raph.exe + all necessary Qt Dlls
(1) You can find the Qt Library the following way:
find_package(Qt5Core [...] 5.6 REQUIRED)
add_executable(someExe file1.cpp)
target_link_libraries(someExe Qt5::Core)
Note that you should keep the original directory stucture of Qt, also containing the Qt cmake scripts, e.g. lib/cmake/Qt5/Qt5Config.cmake
If you want a specific directory to be included when searching for Qt, you can do (before you search for Qt):
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "./your/path")
This can for example be the directory you supply.
(2) You can use cmake's automoc feature. Just add
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
at the beginning of your cmake script. CMake also supports AUTOUIC and AUTORCC. I haven't tried them yet, but the probably work similar.
(3) You can for example add a custom target to your project, that copies the dlls. When you build that target, all the dlls will be copied. The paths of the dlls you can get from the targets that the Qt find script defines (like Qt5::Core).
get_target_property(LOC_R Qt5::Core LOCATION_RELEASE)
get_target_property(LOC_D Qt5::Core LOCATION_DEBUG)
However, you should also scan these target for dependencies (other dlls they depend on). You could write a macro that scans a whole list of targets for the correspondig dlls and adds them to a list, let's call these RELEASE_DLLS and DEBUG_DLLS:
macro(copydlls RELEASE_DLLS DEBUG_DLLS MODULELIST)
foreach(ELEMENT ${${MODULELIST}})
get_target_property(LOC_R ${ELEMENT} LOCATION_RELEASE)
get_target_property(LOC_D ${ELEMENT} LOCATION_DEBUG)
list(APPEND ${RELEASE_DLLS} ${LOC_R})
list(APPEND ${DEBUG_DLLS} ${LOC_D})
get_target_property(DEPENDENCIES_RELEASE ${ELEMENT} IMPORTED_LINK_DEPENDENT_LIBRARIES_RELEASE)
foreach(DEPENDENCY ${DEPENDENCIES_RELEASE})
if(TARGET ${DEPENDENCY})
get_target_property(LOC_R ${DEPENDENCY} LOCATION_RELEASE)
if(${LOC_R} MATCHES ".dll$")
list(APPEND ${RELEASE_DLLS} ${LOC_R})
endif()
endif()
endforeach()
get_target_property(DEPENDENCIES_DEBUG ${ELEMENT} IMPORTED_LINK_DEPENDENT_LIBRARIES_DEBUG)
foreach(DEPENDENCY ${DEPENDENCIES_DEBUG})
if(TARGET ${DEPENDENCY})
get_target_property(LOC_D ${DEPENDENCY} LOCATION_DEBUG)
if(${LOC_D} MATCHES ".dll$")
list(APPEND ${DEBUG_DLLS} ${LOC_D})
endif()
endif()
endforeach()
get_target_property(DEPENDENCIES_RELEASE ${ELEMENT} IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE)
foreach(DEPENDENCY ${DEPENDENCIES_RELEASE})
if(TARGET ${DEPENDENCY})
get_target_property(LOC_R ${DEPENDENCY} LOCATION_RELEASE)
if(${LOC_R} MATCHES ".dll$")
list(APPEND ${RELEASE_DLLS} ${LOC_R})
endif()
endif()
endforeach()
get_target_property(DEPENDENCIES_DEBUG ${ELEMENT} IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG)
foreach(DEPENDENCY ${DEPENDENCIES_DEBUG})
if(TARGET ${DEPENDENCY})
get_target_property(LOC_D ${DEPENDENCY} LOCATION_DEBUG)
if(${LOC_D} MATCHES ".dll$")
list(APPEND ${DEBUG_DLLS} ${LOC_D})
endif()
endif()
endforeach()
endforeach()
endmacro()
Then you could get all the Qt dlls in a list, by calling this macro with:
IF(MSVC)
set(QT_MODULES "Qt5::Core" "Qt5::Gui" "Qt5::Widgets")
set(RELEASE_DLLS)
set(DEBUG_DLLS)
copydlls(RELEASE_DLLS DEBUG_DLLS QT_MODULES)
ENDIF(MSVC)
When you've retrieved that information, you can create your custom target the following way. Let's assume you have all your dll paths in the lists RELEASE_DLLS and DEBUG_DLLS and your executable names as a list in TARGETS. Then you could do something like this:
if(MSVC)
set(COPY_COMMAND_RELEASE "-E copy_if_different ")
set(COPY_COMMAND_DEBUG "-E copy_if_different ")
list(REMOVE_DUPLICATES RELEASE_DLLS)
list(REMOVE_DUPLICATES DEBUG_DLLS)
foreach(DLL ${RELEASE_DLLS})
string(CONCAT COPY_COMMAND_RELEASE "${COPY_COMMAND_RELEASE} \"${DLL}\" ")
endforeach()
foreach(DLL ${DEBUG_DLLS})
string(CONCAT COPY_COMMAND_DEBUG "${COPY_COMMAND_DEBUG} \"${DLL}\" ")
endforeach()
string(CONCAT COPY_COMMAND_RELEASE ${COPY_COMMAND_RELEASE} "\"${CMAKE_CURRENT_BINARY_DIR}/Release\" ")
string(CONCAT COPY_COMMAND_DEBUG ${COPY_COMMAND_DEBUG} "\"${CMAKE_CURRENT_BINARY_DIR}/Debug\" ")
add_custom_target(COPY_DLLS)
foreach(EXECUTABLE ${TARGETS})
add_custom_command(TARGET COPY_DLLS PRE_BUILD COMMAND ${CMAKE_COMMAND} ${COPY_COMMAND_RELEASE} COMMENT "Copying dlls to executable directory...")
add_custom_command(TARGET COPY_DLLS PRE_BUILD COMMAND ${CMAKE_COMMAND} ${COPY_COMMAND_DEBUG} COMMENT "Copying dlls to executable directory...")
endforeach()
endif()
If you want this target to be executed every time one of your other targets is built, you can do:
foreach(EXECUTABLE ${TARGETS})
add_dependencies(${EXECUTABLE} COPY_DLLS)
endforeach()
Don't foget that you must also copy the platforms directory from plugins to your executable folder, for example by adding it to the copy dll target:
add_custom_command(TARGET COPY_DLLS PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PATH_QT_ROOT}/plugins/platforms ${CMAKE_CURRENT_BINARY_DIR}/Debug/platforms
COMMAND ${CMAKE_COMMAND} -E copy_directory ${PATH_QT_ROOT}/plugins/platforms ${CMAKE_CURRENT_BINARY_DIR}/Release/platforms
COMMENT "Copying Qt platforms to executable directory...")
Im trying to build a vala-application together with an own library in the same project using CMake. Building the application works fine, so I've added a new "lib" directory to my project with the following CMakeLists.txt:
# Configure precompile
vala_precompile (LIB_VALA_C ${LIB_NAME}
Session.vala
PACKAGES
gio-2.0
gee-0.8
OPTIONS
--thread
--vapidir=${CMAKE_SOURCE_DIR}/vapi
--target-glib 2.32
GENERATE_VAPI
${LIB_NAME}
GENERATE_HEADER
${CMAKE_PROJECT_NAME}
)
# Add executable
add_library (${LIB_NAME} SHARED ${LIB_VALA_C})
# Set library properties
set_target_properties (${LIB_NAME} PROPERTIES
OUTPUT_NAME ${LIB_NAME}
VERSION ${LIB_SOVERSION}.${LIB_VERSION}
SOVERSION ${LIB_SOVERSION}
)
target_link_libraries (${LIB_NAME} ${LIB_LIBRARIES})
# Installation
install (TARGETS ${LIB_NAME} DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}.pc DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig/)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}.vapi DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/vala/vapi/)
install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/${LIB_NAME}.deps DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/vala/vapi/)
install (FILES ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}.h DESTINATION ${CMAKE_INSTALL_FULL_INCLUDEDIR}/${LIB_NAME}/)
The CMakeLists.txt in the project's root contains the following:
# Project name
project (drop)
# Minimum requirements of build-system
cmake_minimum_required (VERSION 2.8)
cmake_policy (VERSION 2.6)
# Global configuration
set (DATADIR "${CMAKE_INSTALL_PREFIX}/share")
set (PKGDATADIR "${DATADIR}/${CMAKE_PROJECT_NAME}")
set (GETTEXT_PACKAGE "${CMAKE_PROJECT_NAME}")
set (RELEASE_NAME "${CMAKE_PROJECT_NAME}")
set (VERSION "0.1")
set (VERSION_INFO "Release")
set (PREFIX ${CMAKE_INSTALL_PREFIX})
set (DOLLAR "$")
# Library configuration
set (LIB_VERSION 1.0)
set (LIB_SOVERSION 0)
set (LIB_NAME ${CMAKE_PROJECT_NAME}-${LIB_VERSION})
# Cmake-files
list (APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
# Configuration file
configure_file (${CMAKE_SOURCE_DIR}/dropd/config.vala.cmake ${CMAKE_SOURCE_DIR}/dropd/config.vala)
# Check for vala
find_package (Vala REQUIRED)
include (ValaVersion)
ensure_vala_version ("0.18" MINIMUM)
include (ValaPrecompile)
# Disable C compiler warnings
add_definitions (-w)
# Set gettext-package
add_definitions (-DGETTEXT_PACKAGE="${CMAKE_PROJECT_NAME}")
# Check for required dependencies
find_package (PkgConfig)
pkg_check_modules (DEPS REQUIRED granite gthread-2.0 gio-2.0 gee-0.8 avahi-gobject avahi-client)
# Link the avahi library
add_definitions (-lavahi)
# Link dependencies
add_definitions (${DEPS_CFLAGS})
add_definitions (${LIB_CFLAGS})
link_libraries (${DEPS_LIBRARIES})
link_directories (${DEPS_LIBRARY_DIRS})
link_directories (${LIB_LIBRARY_DIRS})
# Load directories
add_subdirectory (dropd)
add_subdirectory (lib)
add_subdirectory (po)
add_subdirectory (data)
add_subdirectory (schemas)
When building the project now the main application still builds without problems, but when the build of the library begins this error appears (translated):
make[2]: *** No rule to make »../lib/drop-1.0«,
required by »lib/drop-1.0«. End.
make[1]: *** [lib/CMakeFiles/drop-1.0.dir/all] Errors 2
make: *** [all] Errors 2
Badly Im not that familar with CMake and don't get what that error message means, neither what is causing it.
I have already compared my CMakeLists.txt files with them in another project that's also built out of a 'normal' application and one library, but I couldn't find the difference that makes my code not working: http://bazaar.launchpad.net/~wingpanel-devs/wingpanel/trunk/files/head:/
It would be very nice if you could give me some tips what I could have missed in the CMake-Files.
For the ones with the same problem: I've now solved the issue myself with removing the ${LIB_NAME} from the line vala_precompile (LIB_VALA_C ${LIB_NAME}. Im still not sure what's happening here, but this "solution" seemed to work.
Better ways to solve this issue are still appreciated. ;)
I have the following situation: a Project A depends on a Project B, but both are built at the same time. Project A has to include the includes of project B and it needs also to link its libraries. Up to now I've tried this way:
ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/other_project other_project)
and then:
INCLUDE_DIRECTORIES(includ ${CMAKE_SOURCE_DIR}/other_project/include})
LIST(APPEND LINK_LIBS other_project)
in the CMakeLists.txt of Project A
but it doesn't seem to work, the compiler also gives me error when including the headers of Project B saying that they do not exist.
What is the right way to add dependencies in A? How should the CMakeLists.txt look like?
EDIT:
as suggested in the comments, this question was addressed in this, however I'd like to see an example of how to use it in a CMakeList.txt file.
The following is a simple example which builds zlib and then builds libxml2 which depends on the zlib we build. One thing to note, I quickly pulled this example from stuff I've done before. The libxml2 example uses make, thus will only actually build on a system which has it, e.g. Linux, Mac ...
Here is the proposed directory structure for this example ...
src/
-- CMakeLists.txt
CMake/
---- External_ZLib.cmake
---- External_libxml2.cmake
Dowloads/ ( no need to create this directory, CMake will do it for you )
build/ ( Out of source build to prevent littering source tree )
Files:
CMakeLists.txt
# Any version that supports ExternalProject should do
cmake_minimum_required( VERSION 3.1)
project(test_ext_proj)
set(test_ext_proj_CMAKE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
set(CMAKE_MODULE_PATH ${test_ext_proj_CMAKE_DIR} ${CMAKE_MODULE_PATH})
set(test_ext_proj_BUILD_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install)
set(test_ext_proj_DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Downloads CACHE PATH "Directory to store downloaded tarballs.")
include(ExternalProject)
include(External_ZLib)
include(External_libxml2)
External_ZLib.cmake:
set(ZLib_version 1.2.8)
set(ZLib_url "http://zlib.net/zlib-${ZLib_version}.tar.gz")
set(ZLib_md5 "44d667c142d7cda120332623eab69f40")
ExternalProject_Add(ZLib
URL ${ZLib_url}
URL_MD5 ${ZLib_md5}
PREFIX ${vision-tpl_BUILD_PREFIX}
DOWNLOAD_DIR ${test_ext_proj_DOWNLOAD_DIR}
INSTALL_DIR ${test_ext_proj_BUILD_INSTALL_PREFIX}
CMAKE_GENERATOR ${gen}
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX:PATH=${test_ext_proj_BUILD_INSTALL_PREFIX}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}
)
#This variable is required so other packages can find it.
set(ZLIB_ROOT ${test_ext_proj_BUILD_INSTALL_PREFIX} CACHE PATH "" FORCE)
External_libxml2.cmake:
set(libxml2_release "2.9")
set(libxml2_patch_version 0)
set(libxml2_url "ftp://xmlsoft.org/libxml2/libxml2-sources-${libxml2_release}.${libxml2_patch_version}.tar.gz")
set(libxml2_md5 "7da7af8f62e111497d5a2b61d01bd811")
#We need to state that we're dependent on ZLib so build order is correct
set(_XML2_DEPENDS ZLib)
#This build requires make, ensure we have it, or error out.
if(CMAKE_GENERATOR MATCHES ".*Makefiles")
set(MAKE_EXECUTABLE "$(MAKE)")
else()
find_program(MAKE_EXECUTABLE make)
if(NOT MAKE_EXECUTABLE)
message(FATAL_ERROR "Could not find 'make', required to build libxml2.")
endif()
endif()
ExternalProject_Add(libxml2
DEPENDS ${_XML2_DEPENDS}
URL ${libxml2_url}
URL_MD5 ${libxml2_md5}
PREFIX ${test_ext_proj_BUILD_PREFIX}
DOWNLOAD_DIR ${test_ext_proj_DOWNLOAD_DIR}
INSTALL_DIR ${test_ext_proj_BUILD_INSTALL_PREFIX}
BUILD_IN_SOURCE 1
CONFIGURE_COMMAND ./configure
--prefix=${test_ext_proj_BUILD_INSTALL_PREFIX}
--with-zlib=${ZLIB_ROOT}
BUILD_COMMAND ${MAKE_EXECUTABLE}
INSTALL_COMMAND ${MAKE_EXECUTABLE} install
)