Deploy icu libraries when linking a cmake project with Qt5 - c++

I've the following CMakeLists.txt for creating a little application:
cmake_minimum_required (VERSION 3.5.0)
project (sampleapp)
# Setting project flags
set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set (CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/lib)
set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/bin)
set (CMAKE_INCLUDE_CURRENT_DIR ON)
set (CMAKE_AUTOMOC ON)
# Finding needed packages
find_package (Qt5Widgets REQUIRED)
find_package (Qt5Core REQUIRED)
find_package (Qt5Gui REQUIRED)
# Setting project files
include_directories (${CMAKE_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR})
file (GLOB_RECURSE PROJECT_SRC *.cpp)
# Creating project
add_executable(${PROJECT_NAME} ${PROJECT_SRC})
# Linking dependencies
target_link_libraries (${PROJECT_NAME} somelibrary Qt5::Widgets Qt5::Gui Qt5::Core)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${PROJECT_NAME}>)
When I run it and then build the application the Qt dlls are copied into target folder. In particular I copy:
Qt5Core.dll
Qt5Gui.dll
Qt5Widgets.dll
When I run the application it does not start anyway because the ICU libraries needed for Qt are not copied. When I start the application, Windows tells me that following libraries are missing:
icuin53.dll
icuuc53.dll
If I copy these libraries manually from Qt insallation folder it works (ok, I've an error regarding "platform plugins windows" missing but it's another story).
Is there a way to copy the icu libraries in a standard way, like the post build commands that I'm using for copying libraries? Or what's the best way to copy them in a transparent way, if possible (CMake can know what are dependencies of Qt and copy them where Qt are needed)?

Instead of copying each dll by hand, you can install all Qt dependencies using windeployqt, the tool provided with Qt for deployment on Windows.
You can first declare windeployqt as an imported executable:
find_package(Qt5
# ...
)
if(Qt5_FOUND AND WIN32 AND TARGET Qt5::qmake AND NOT TARGET Qt5::windeployqt)
get_target_property(_qt5_qmake_location
Qt5::qmake IMPORTED_LOCATION
)
execute_process(
COMMAND "${_qt5_qmake_location}" -query QT_INSTALL_PREFIX
RESULT_VARIABLE return_code
OUTPUT_VARIABLE qt5_install_prefix
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(imported_location "${qt5_install_prefix}/bin/windeployqt.exe")
if(EXISTS ${imported_location})
add_executable(Qt5::windeployqt IMPORTED)
set_target_properties(Qt5::windeployqt PROPERTIES
IMPORTED_LOCATION ${imported_location}
)
endif()
endif()
Now the imported executable can be used as follows:
add_executable(foo
# ...
)
if(TARGET Qt5::windeployqt)
add_custom_command(TARGET foo
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/windeployqt"
COMMAND set PATH=%PATH%$<SEMICOLON>${qt5_install_prefix}/bin
COMMAND Qt5::windeployqt --dir "${CMAKE_CURRENT_BINARY_DIR}/windeployqt" "$<TARGET_FILE:foo>"
)
install(
DIRECTORY
"${CMAKE_CURRENT_BINARY_DIR}/windeployqt/"
DESTINATION ${FOO_INSTALL_RUNTIME_DESTINATION}
)
endif()

Related

FetchContent vs ExternalProject

I am building a project with Cmake and use FetchContent to manage dependencies. For several reasons I cannot depend on system-wide installed packages, so this package helps a lot. It allows me to do things like this:
cmake_minimum_required(VERSION 3.14)
project(dummy LANGUAGES C CXX)
include(FetchContent)
FetchContent_Declare(nlohmann
GIT_REPOSITORY https://github.com/onavratil-monetplus/json
GIT_TAG v3.7.3
)
FetchContent_MakeAvailable(nlohmann)
add_executable(dummy main.cpp)
target_link_libraries(dummy PUBLIC nlohmann_json::nlohmann_json)
Now this works nicely as long as the repo is a cmake project with CMakeLists.txt. I would love to use similar approach for non-cmake projects, such as Botan library. Apparently
FetchContent_Declare(botan
GIT_REPOSITORY https://github.com/onavratil-monetplus/botan
GIT_TAG 2.17.2
)
FetchContent_MakeAvailable(botan)
does not really do the job, the build doesnt run since its not a cmake project. One would consider adding
CONFIGURE_COMMAND "<SOURCE_DIR>/configure.py --prefix=<BINARY_DIR>"
BUILD_COMMAND "cd <SOURCE_DIR> && make"
or something similar to the declare command, yet the FetchContent docs explicitly says that these particular arguments are ignored when passed to FetchContent.
Now the struggle is obvious - how to properly use FetchContent in this scenario? I was considering using ExternalProject_Add after the fetchcontent, yet then fetchcontent seems useless (ExternalProject can download git repo as well). Moreover, I would like to use some of the targets of botan at config time (if it makes sense).
I'm facing the same problem. Since the Botan library does not use the CMake build system internally, we cannot use the Botan "targets". But it is possible to build the Botan library at CMake configure time and use library and header files. Here is my solution (minimal configuration, works only for MS Visual Studio):
cmake_minimum_required (VERSION 3.20)
if(WIN32)
if(NOT (${CMAKE_BUILD_TYPE} STREQUAL "Release"))
message(FATAL_ERROR "This configuration only works for a Release build")
endif()
# set paths
set(BOTAN_LIB_ROOT_DIR "${CMAKE_SOURCE_DIR}/external/botan")
set(BOTAN_LIB_REPOS_DIR "${BOTAN_LIB_ROOT_DIR}/repos")
set(BOTAN_LIB_FCSTUFF_DIR "${BOTAN_LIB_ROOT_DIR}/cmake-fetchcontent-stuff")
set(BOTAN_LIB_INSTALL_DIR "${BOTAN_LIB_ROOT_DIR}-install")
# download and unpack Botan library
include(FetchContent)
FetchContent_Declare(
botan
GIT_REPOSITORY https://github.com/randombit/botan.git
GIT_TAG 2.19.1
PREFIX ${BOTAN_LIB_FCSTUFF_DIR}
SOURCE_DIR ${BOTAN_LIB_REPOS_DIR}
)
set(FETCHCONTENT_QUIET OFF CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(botan)
# find Python3 Interpreter and run build, testing and installation
if(${botan_POPULATED} AND MSVC AND NOT EXISTS "${BOTAN_LIB_INSTALL_DIR}/lib/botan.lib")
find_package(Python3 COMPONENTS Interpreter)
if(NOT ${Python3_Interpreter_FOUND})
message(FATAL_ERROR "Python3 Interpreter NOT FOUND")
endif()
execute_process(
COMMAND ${Python3_EXECUTABLE} configure.py --cc=msvc --os=windows --prefix=${BOTAN_LIB_INSTALL_DIR}
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake check
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
execute_process(
COMMAND nmake install
WORKING_DIRECTORY ${BOTAN_LIB_REPOS_DIR}
COMMAND_ECHO STDOUT
)
endif()
endif()
add_executable (main "main.cpp")
if(WIN32)
target_include_directories(main PUBLIC "${BOTAN_LIB_INSTALL_DIR}/include/botan-2")
target_link_libraries(main PUBLIC "${BOTAN_LIB_INSTALL_DIR}/lib/botan.lib")
configure_file("${BOTAN_LIB_INSTALL_DIR}/bin/botan.dll"
"${CMAKE_CURRENT_BINARY_DIR}/botan.dll"
COPYONLY
)
install(TARGETS main DESTINATION bin)
install(FILES "${BOTAN_LIB_INSTALL_DIR}/bin/botan.dll" DESTINATION bin)
endif()
Here is the full version: https://github.com/weenchvd/cmake-build-botan-lib

CMAKE + SQLite3.dll

Anyone know how to copy the SQLite3.dll into the executable directory using CMAKE? I am able to use sqlite in generated VS project but when i try to run the exe it cannot find the dll.
I am guessing that CMAKE would write a copy command into the post-build events in the VS project settings? But how is that done through CMAKE.
cmake_minimum_required(VERSION 3.10)
add_executable(APP)
target_sources(APP
PRIVATE
include/box.hpp
src/box.cpp
src/main.cpp
)
target_include_directories(APP PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
# SQlite
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/Modules)
set(SQLite3_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite3/include)
set(SQLite3_LIBRARY ${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite3/libraries/win10/x64)
find_package (SQLite3)
if (SQLITE3_FOUND)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite3/include)
list(APPEND EXTRA_LIBS ${CMAKE_CURRENT_SOURCE_DIR}/../external/sqlite3/libraries/win10/x64/sqlite3.lib)
endif (SQLITE3_FOUND)
list(APPEND EXTRA_LIBS LIBCORE)
list(APPEND EXTRA_LIBS Boost::filesystem)
target_link_libraries(APP PRIVATE ${EXTRA_LIBS})
# INSTALL
install(TARGETS APP DESTINATION ${PROJECT_BINARY_DIR}/TEMP/bin)
It is possible to use cmake in CMakeLists.txt as a tool and it has file copy functionality
Something like this might be a start
set(source_file "D:/temp/from/sqlite3.dll")
set(target_file "D:\\temp\\to\\sqlite3.dll")
execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different "${source_file}" "${target_file}" RESULT_VARIABLE sResult )
CMake tutorial

Create Qt translation files with CMake

I'm having a problem when i'm trying to add the process of generating the translations inside the CMake process.
Now i have the following CMakeLists.txt:
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/defines.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/defines.h)
file(GLOB_RECURSE UI_FILES *.ui)
file(GLOB_RECURSE CODE_FILES *.cpp)
qt5_wrap_ui(UI_HEADERS ${UI_FILES})
# Qt5LinguistTools
find_package(Qt5LinguistTools)
FILE(GLOB TS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/../resources/langs/*.ts")
QT5_create_translation(QM_FILES ${CODE_FILES} ${TS_FILES})
# Resources
qt5_add_resources(RESOURCE_FILES ../resources/resources.qrc)
# Windows application icon
if (WIN32)
set(WINDOWS_RES_FILE ${CMAKE_CURRENT_BINARY_DIR}/resources.obj)
if (MSVC)
add_custom_command(OUTPUT ${WINDOWS_RES_FILE}
COMMAND rc.exe /fo ${WINDOWS_RES_FILE} resources.rc
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/win
)
else()
add_custom_command(OUTPUT ${WINDOWS_RES_FILE}
COMMAND windres.exe resources.rc ${WINDOWS_RES_FILE}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/win
)
endif()
endif()
#Move Qm files to resources langs folder
install(FILES ${QM_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/../resources/langs)
add_executable(${CMAKE_PROJECT_NAME} WIN32
${QM_FILES}
${UI_HEADERS}
${CODE_FILES}
${RESOURCE_FILES}
${WINDOWS_RES_FILE}
)
target_link_libraries(${CMAKE_PROJECT_NAME}
Qt5::Widgets
QtAwesome
)
if (UNIX)
install(TARGETS ${CMAKE_PROJECT_NAME}
RUNTIME DESTINATION bin)
elseif (WIN32)
install(TARGETS ${CMAKE_PROJECT_NAME}
DESTINATION .)
endif()
It seems that this code generates correctly the .qm files, but not before being read by the resources file. So I'm getting an error: NMAKE : fatal error U1073: don't know how to make '..\..\..\resources\langs\lang_en_US.qm'
Maybe I'm not doing that on the right way or i need to read the language files from other place that's not inside the resources file.
Could you provide me an advice on how to generate the QM files and adding them on the build process.
From the documentation:
Updating the translations can be done by adding the qm_files to the source list of your library/executable, so they are always updated, or by adding a custom target to control when they get updated/generated.
You can create custom targets and add dependencies:
add_custom_target(translations ALL DEPENDS ${QM_FILES})
add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES})
add_dependencies(resources translations)
add_executable(${CMAKE_PROJECT_NAME} WIN32
${UI_HEADERS}
${CODE_FILES}
${RESOURCE_FILES}
${WINDOWS_RES_FILE}
)
add_dependencies(${CMAKE_PROJECT_NAME} resources)
This is what I'm doing for QOwnNotes: https://github.com/pbek/QOwnNotes/blob/develop/src/CMakeLists.txt
# Translation files
SET(QON_TS_FILES
languages/QOwnNotes_en.ts
languages/QOwnNotes_de.ts
languages/QOwnNotes_fr.ts
languages/QOwnNotes_pl.ts
languages/QOwnNotes_zh.ts
languages/QOwnNotes_ru.ts
languages/QOwnNotes_pt.ts
languages/QOwnNotes_es.ts
languages/QOwnNotes_nl.ts
languages/QOwnNotes_hu.ts
languages/QOwnNotes_ja.ts
languages/QOwnNotes_it.ts
languages/QOwnNotes_ar.ts
)
qt5_add_translation(QON_QM_FILES ${QON_TS_FILES})
add_custom_target(translations DEPENDS ${QON_QM_FILES})
if(NOT QT_TRANSLATIONS_DIR)
# If this directory is missing, we are in a Qt5 environment.
# Extract the qmake executable location
get_target_property(QT5_QMAKE_EXECUTABLE Qt5::qmake IMPORTED_LOCATION)
# Ask Qt5 where to put the translations
execute_process( COMMAND ${QT5_QMAKE_EXECUTABLE} -query QT_INSTALL_TRANSLATIONS
OUTPUT_VARIABLE qt_translations_dir OUTPUT_STRIP_TRAILING_WHITESPACE )
# make sure we have / and not \ as qmake gives on windows
file( TO_CMAKE_PATH "${qt_translations_dir}" qt_translations_dir)
set( QT_TRANSLATIONS_DIR ${qt_translations_dir} CACHE PATH
"The location of the Qt translations" FORCE)
endif()
install(FILES ${QON_QM_FILES}
DESTINATION ${QT_TRANSLATIONS_DIR})
add_executable(QOwnNotes ${SOURCE_FILES} ${RESOURCE_ADDED} ${QON_QM_FILES})
Does this help you?

CMake - How Can I link to an external library that I have packed with my project?

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...")

CMakelists.txt is ridiculously complex to get windows and mac to work, is there a better way?

I have been getting a CMakeLists.txt together to compile what right now is an SFML sample in preparation to do my own source code. It feels like a hack, even though it works (Mac Makefile, VS nmake, VS solution) right now.
The main repository is at https://github.com/iaefai/Spider-Fish/
Any suggestions are welcome.
cmake_minimum_required(VERSION 2.8)
PROJECT(Spider-Fish)
FIND_PACKAGE(OpenGL REQUIRED)
FIND_PACKAGE(SFML REQUIRED)
IF (WIN32)
# Windows
link_directories(${SFML_INCLUDE_DIR}/../lib)
set(RESOURCE_HANDLER ${CMAKE_CURRENT_SOURCE_DIR}/src/windows/resources.cpp)
# link_directories(${FIND_SFML_LIB_PATHS})
ELSEIF(APPLE)
# Mac
SET(RESOURCE_HANDLER ${CMAKE_CURRENT_SOURCE_DIR}/src/mac/resources.mm)
SET(MACOSX_BUNDLE_GUI_IDENTIFER "com.iaefai.Spider-Fish")
SET(MACOSX_BUNDLE_BUNDLE_NAME ${PROJECT_NAME})
if (NOT CMAKE_OSX_ARCHITECTURES)
set(CMAKE_OSX_ARCHITECTURES "i386;x86_64"
CACHE STRING "Build architectures for OSX" FORCE)
endif()
if(EXISTS /Developer/SDKs/MacOSX10.7.sdk)
set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.7.sdk"
CACHE STRING "Defaults to 10.7" FORCE)
else()
# use default SDK
endif()
find_library(COCOA_LIB Cocoa)
SET(EXTRA_LIBS ${COCOA_LIB} ${OPENGL_LIBRARIES})
ELSE()
# Linux // Assumed??
ENDIF()
#include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include})
include_directories(${SFML_INCLUDE_DIR})
SET(RESOURCES ${CMAKE_CURRENT_SOURCE_DIR}/assets/background.jpg
${CMAKE_CURRENT_SOURCE_DIR}/assets/blur.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/colorize.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/edge.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/fisheye.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/nothing.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/pixelate.sfx
${CMAKE_CURRENT_SOURCE_DIR}/assets/sansation.ttf
${CMAKE_CURRENT_SOURCE_DIR}/assets/sprite.png
${CMAKE_CURRENT_SOURCE_DIR}/assets/wave.jpg
${CMAKE_CURRENT_SOURCE_DIR}/assets/wave.sfx)
SET (SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/Shader.cpp)
#SET (HEADERS include/resources.h)
add_executable(${PROJECT_NAME} ${SOURCES} ${RESOURCE_HANDLER})
The biggest hack seems to be the stuff to copy resources. That would be ideal to have a special command that could do that on multiplatform. Not entirely certain how to do that — I suspect a set_target_resources would be a good name.
IF (APPLE)
set_target_properties(${PROJECT_NAME}
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/src/mac/Spider-Fish-Info.plist
MACOSX_BUNDLE TRUE)
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND echo copying resources...
#${RESOURCES}
COMMAND mkdir -p ./${PROJECT_NAME}.app/Contents/Resources
COMMAND cp ${RESOURCES} ./${PROJECT_NAME}.app/Contents/Resources
)
# add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND echo ${PROJECT_NAME}.app/Contents/Resources)
ENDIF (APPLE)
IF (WIN32)
set_target_properties(${PROJECT_NAME}
PROPERTIES
WIN32_EXECUTABLE FALSE)
I would worry about this custom stuff on windows because of how specialized it is getting.
set(EXTRA_LIBS sfml-main ${OPENGL_LIBRARIES})
# note we can add stuff to ADDITIONAL_MAKE_CLEAN_FILES
string(COMPARE EQUAL ${CMAKE_GENERATOR} "NMake Makefiles" NMAKE)
if (NMAKE)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND echo copying dlls...
COMMAND copy ${SFML_INCLUDE_DIR}\\..\\bin\\*.dll .
COMMAND echo copying resources... from ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND -mkdir resources
COMMAND copy \"${CMAKE_CURRENT_SOURCE_DIR}\\assets\\*.*\" resources)
else ()
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND echo copying dlls...
COMMAND copy ${SFML_INCLUDE_DIR}\\..\\bin\\*.dll .
COMMAND echo copying resources... from ${CMAKE_CURRENT_SOURCE_DIR}
# Visual Studio does not support the '-' to ignore errors
COMMAND rmdir /s /q resources
COMMAND mkdir resources
COMMAND copy \"${CMAKE_CURRENT_SOURCE_DIR}\\assets\\*.*\" resources)
endif (NMAKE)
ENDIF (WIN32)
#if (APPLE)
target_link_libraries(${PROJECT_NAME}
sfml-system
sfml-window
sfml-network
sfml-graphics
sfml-audio
${EXTRA_LIBS})
#endif (APPLE)
Have you tried using the INSTALL command instead of the custom post build steps.