From d2e682345144a0976279ce71f398984f955f2fbc Mon Sep 17 00:00:00 2001 From: Tamas Kenez Date: Mon, 22 Jun 2015 14:06:50 +0200 Subject: [PATCH] cmake: install config-module Installs a config module if CMake verion >= 2.8.12. The config-module creates the import library targets built in the project (glew, glew_s, glewmx, glewmx_s) but in accordance with the FindGLEW module shipped with CMake, it also creates GLEW::GLEW and GLEW::GLEWMX. GLEW::GLEW and GLEW::GLEWMX will be simply copies of glew/glewmx or glew_s/glewmx_s. If both versions are available they alias the shared versions. The default behaviour can be changed either when installing or when using the package: - Set BUILD_SHARED_LIBS to OFF or ON when building and installing GLEW. This controls which libraries (shared or static) will be installed (and not which will be built). - Set GLEW_USE_STATIC_LIBS to OFF or ON before calling `find_package(GLEW CONFIG REQUIRED)` to force the config-module to create GLEW::GLEW and GLEWMX as aliases to glew/glewmx or glew_s/glewmx_s The script ./cmake-testbuild.sh is added to test the CMake build and config-module. See instructions there. --- .gitattributes | 1 + .gitignore | 1 + build/cmake/CMakeLists.txt | 35 +++++++- .../cmake/CopyImportedTargetProperties.cmake | 88 +++++++++++++++++++ build/cmake/glew-config.cmake | 46 ++++++++++ build/cmake/testbuild/CMakeLists.txt | 24 +++++ build/cmake/testbuild/main.c | 23 +++++ cmake-testbuild.sh | 70 +++++++++++++++ 8 files changed, 287 insertions(+), 1 deletion(-) create mode 100644 build/cmake/CopyImportedTargetProperties.cmake create mode 100644 build/cmake/glew-config.cmake create mode 100644 build/cmake/testbuild/CMakeLists.txt create mode 100644 build/cmake/testbuild/main.c create mode 100755 cmake-testbuild.sh diff --git a/.gitattributes b/.gitattributes index 6bd6429..b49408f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,4 @@ *.png binary build/*/* text eol=crlf CMakeLists.txt text eol=lf +build/cmake/* text eol=lf diff --git a/.gitignore b/.gitignore index 0cdd347..8e9527a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ /bin /lib /tmp +/out diff --git a/build/cmake/CMakeLists.txt b/build/cmake/CMakeLists.txt index fdeab0e..1563f9f 100644 --- a/build/cmake/CMakeLists.txt +++ b/build/cmake/CMakeLists.txt @@ -10,6 +10,8 @@ if (COMMAND cmake_policy) cmake_policy (SET CMP0003 NEW) endif() +set(CMAKE_DEBUG_POSTFIX d) + option (BUILD_UTILS "utilities" ON) set (GLEW_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../..) @@ -55,7 +57,29 @@ set_target_properties (glewmx_s PROPERTIES COMPILE_DEFINITIONS "GLEW_STATIC;GLEW target_link_libraries (glewmx ${GLEW_LIBRARIES}) target_link_libraries (glewmx_s ${GLEW_LIBRARIES}) -install ( TARGETS glew glew_s glewmx glewmx_s +if(CMAKE_VERSION VERSION_LESS 2.8.12) + set(MAYBE_EXPORT "") +else() + target_compile_definitions(glew_s INTERFACE "GLEW_STATIC") + target_compile_definitions(glewmx INTERFACE "GLEW_MX") + target_compile_definitions(glewmx_s INTERFACE "GLEW_STATIC;GLEW_MX") + foreach(t glew glew_s glewmx glewmx_s) + target_include_directories(${t} PUBLIC $) + endforeach() + set(MAYBE_EXPORT EXPORT glew-targets) +endif() + +set(targets_to_install "") +if(NOT DEFINED BUILD_SHARED_LIBS OR BUILD_SHARED_LIBS) + list(APPEND targets_to_install glew glewmx) +endif() + +if(NOT DEFINED BUILD_SHARED_LIBS OR NOT BUILD_SHARED_LIBS) + list(APPEND targets_to_install glew_s glewmx_s) +endif() + +install ( TARGETS ${targets_to_install} + ${MAYBE_EXPORT} RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX} @@ -95,3 +119,12 @@ install (FILES ${GLEW_DIR}/include/GL/glew.h ${GLEW_DIR}/include/GL/glxew.h DESTINATION include/GL) + +if(MAYBE_EXPORT) + install(EXPORT glew-targets DESTINATION lib/cmake/glew + NAMESPACE GLEW::) + install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/glew-config.cmake + ${CMAKE_CURRENT_SOURCE_DIR}/CopyImportedTargetProperties.cmake + DESTINATION lib/cmake/glew) +endif() diff --git a/build/cmake/CopyImportedTargetProperties.cmake b/build/cmake/CopyImportedTargetProperties.cmake new file mode 100644 index 0000000..a7ade98 --- /dev/null +++ b/build/cmake/CopyImportedTargetProperties.cmake @@ -0,0 +1,88 @@ +#.rst: +# CopyImportedTargetProperties +# -------------------------- +# +# Copies the `INTERFACE*` and `IMPORTED*` properties from a target +# to another one. +# This function can be used to duplicate an `IMPORTED` or an `ALIAS` library +# with a different name since ``add_library(... ALIAS ...)`` does not work +# for those targets. +# +# :: +# +# copy_imported_target_properties( ) +# +# The function copies all the `INTERFACE*` and `IMPORTED*` target +# properties from `` to ``. +# +# The function uses the `IMPORTED_CONFIGURATIONS` property to determine +# which configuration-dependent properties should be copied +# (`IMPORTED_LOCATION_`, etc...) +# +# Example: +# +# Internally the CMake project of ZLIB builds the ``zlib`` and +# ``zlibstatic`` targets which can be exported in the ``ZLIB::`` namespace +# with the ``install(EXPORT ...)`` command. +# +# The config-module will then create the import libraries ``ZLIB::zlib`` and +# ``ZLIB::zlibstatic``. To use ``ZLIB::zlibstatic`` under the standard +# ``ZLIB::ZLIB`` name we need to create the ``ZLIB::ZLIB`` imported library +# and copy the appropriate properties: +# +# add_library(ZLIB::ZLIB STATIC IMPORTED) +# copy_imported_target_properties(ZLIB::zlibstatic ZLIB::ZLIB) +# + +function(copy_imported_target_properties src_target dest_target) + + set(config_dependent_props + IMPORTED_IMPLIB + IMPORTED_LINK_DEPENDENT_LIBRARIES + IMPORTED_LINK_INTERFACE_LANGUAGES + IMPORTED_LINK_INTERFACE_LIBRARIES + IMPORTED_LINK_INTERFACE_MULTIPLICITY + IMPORTED_LOCATION + IMPORTED_NO_SONAME + IMPORTED_SONAME + ) + + # copy configuration-independent properties + foreach(prop + ${config_dependent_props} + IMPORTED_CONFIGURATIONS + INTERFACE_AUTOUIC_OPTIONS + INTERFACE_COMPILE_DEFINITIONS + INTERFACE_COMPILE_FEATURES + INTERFACE_COMPILE_OPTIONS + INTERFACE_INCLUDE_DIRECTORIES + INTERFACE_LINK_LIBRARIES + INTERFACE_POSITION_INDEPENDENT_CODE + INTERFACE_SOURCES + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES + ) + get_property(is_set TARGET ${src_target} PROPERTY ${prop} SET) + if(is_set) + get_target_property(v ${src_target} ${prop}) + set_target_properties(${dest_target} PROPERTIES ${prop} "${v}") + # message(STATUS "set_target_properties(${dest_target} PROPERTIES ${prop} ${v})") + endif() + endforeach() + + # copy configuration-dependent properties + get_target_property(imported_configs ${src_target} + IMPORTED_CONFIGURATIONS) + + foreach(config ${imported_configs}) + foreach(prop_prefix ${config_dependent_props}) + set(prop ${prop_prefix}_${config}) + get_property(is_set TARGET ${src_target} PROPERTY ${prop} SET) + if(is_set) + get_target_property(v ${src_target} ${prop}) + set_target_properties(${dest_target} + PROPERTIES ${prop} "${v}") + # message(STATUS "set_target_properties(${dest_target} PROPERTIES ${prop} ${v})") + endif() + endforeach() + endforeach() +endfunction() diff --git a/build/cmake/glew-config.cmake b/build/cmake/glew-config.cmake new file mode 100644 index 0000000..8d2907a --- /dev/null +++ b/build/cmake/glew-config.cmake @@ -0,0 +1,46 @@ +# This config-module creates the following import libraries: +# +# - GLEW::glew and GLEW::glewmx shared libs +# - GLEW::glew_s and GLEW::glewmx_s static libs +# +# Additionally GLEW::GLEW and GLEW::GLEWMX will be created as an +# copy of either the shared (default) or the static libs. +# +# Dependending on the setting of BUILD_SHARED_LIBS at GLEW build time +# either the static or shared versions may not be available. +# +# Set GLEW_USE_STATIC_LIBS to OFF or ON to force using the shared +# or static libs for GLEW::GLEW and GLEW::GLEWMX +# + +include(${CMAKE_CURRENT_LIST_DIR}/glew-targets.cmake) +include(${CMAKE_CURRENT_LIST_DIR}/CopyImportedTargetProperties.cmake) + +# decide which import library (glew/glew_s and glewmx/glewmx_s) +# needs to be copied to GLEW::GLEW and GLEW::GLEWMX +set(_glew_target_postfix "") +set(_glew_target_type SHARED) +if(DEFINED GLEW_USE_STATIC_LIBS) + # if defined, use only static or shared + if(GLEW_USE_STATIC_LIBS) + set(_glew_target_postfix "_s") + endif() + # else use static only if no shared +elseif(NOT TARGET GLEW::glew AND TARGET GLEW::glew_s) + set(_glew_target_postfix "_s") +endif() +if(_glew_target_postfix STREQUAL "") + set(_glew_target_type SHARED) +else() + set(_glew_target_type STATIC) +endif() + +# CMake doesn't allow creating ALIAS lib for an IMPORTED lib +# so create imported ones and copy the properties +foreach(_glew_target glew glewmx) + set(_glew_src_target "GLEW::${_glew_target}${_glew_target_postfix}") + string(TOUPPER "GLEW::${_glew_target}" _glew_dest_target) + add_library(${_glew_dest_target} ${_glew_target_type} IMPORTED) + # message(STATUS "add_library(${_glew_dest_target} ${_glew_target_type} IMPORTED)") + copy_imported_target_properties(${_glew_src_target} ${_glew_dest_target}) +endforeach() diff --git a/build/cmake/testbuild/CMakeLists.txt b/build/cmake/testbuild/CMakeLists.txt new file mode 100644 index 0000000..1bb69b4 --- /dev/null +++ b/build/cmake/testbuild/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 2.8.12) +project(glew-cmake-test) + +find_package(GLEW REQUIRED CONFIG) +find_package(OpenGL REQUIRED) + +add_executable(cmake-test main.c) +set_target_properties(cmake-test PROPERTIES DEBUG_POSTFIX _d) +target_link_libraries(cmake-test PRIVATE GLEW::GLEW ${OPENGL_LIBRARIES}) +target_include_directories(cmake-test PRIVATE ${OPENGL_INCLUDE_DIR}) + +if(CMAKE_VERSION VERSION_LESS 3.0) + set(cgex $) +else() + set(cgex $) +endif() + +target_compile_definitions(cmake-test PRIVATE + -DGLEW_CMAKE_TEST_CONFIG=${cgex} + -DGLEW_CMAKE_TEST_TARGET_FILE_NAME=$ + -DGLEW_CMAKE_TEST_TARGET_TYPE=$ + ) + +install(TARGETS cmake-test DESTINATION bin) diff --git a/build/cmake/testbuild/main.c b/build/cmake/testbuild/main.c new file mode 100644 index 0000000..5975817 --- /dev/null +++ b/build/cmake/testbuild/main.c @@ -0,0 +1,23 @@ +#include + +#include +#include + +#define S(x) SS(x) +#define SS(x) #x + +int main(int argc, char* argv[]) { + printf("GLEW CMake test, %s build\n", + S(GLEW_CMAKE_TEST_CONFIG)); + printf("-- linked to %s which is %s\n", + S(GLEW_CMAKE_TEST_TARGET_FILE_NAME), + S(GLEW_CMAKE_TEST_TARGET_TYPE)); + const GLubyte* v = glewGetString(GLEW_VERSION); + if(v) { + printf("-- glewGetString(GLEW_VERSION) returns %s\n-- test passed.\n", v); + return EXIT_SUCCESS; + } else { + printf("-- glewGetString(GLEW_VERSION) returns NULL\n-- test failed.\n"); + return EXIT_FAILURE; + } +} diff --git a/cmake-testbuild.sh b/cmake-testbuild.sh new file mode 100755 index 0000000..eceae8d --- /dev/null +++ b/cmake-testbuild.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +# This script tests the CMake build: +# +# - builds the main CMakeLists.txt +# - builds and runs a small test app in a separate build tree so +# the config-module is tested, too +# +# Options (environment variables): +# +# - The variable BUILD_SHARED_LIBS will be forwarded to the CMake project +# that builds and installs the GLEW libraries. Set BUILD_SHARED_LIBS to +# ON or OFF to install only static or shared libs. Leave it unset to +# install both. +# +# Note: BUILD_SHARED_LIBS controls only what to install not what to build. +# +# - GLEW_USE_STATIC_LIBS will be forwarded to the test project that calls +# `find_package` to find GLEW. Set GLEW_USE_STATIC LIBS to ON or OFF force +# finding the shared or static versions of GLEW. Leave it unset to find +# the shared or what is available. +# +# Examples: +# +# Build & install shared + static, find default (shared) +# +# ./cmake-testbuild.shh +# +# Build & install shared + static, find static +# +# GLEW_USE_STATIC_LIBS=ON ./cmake-testbuild.sh +# +# Install static only (still build both) +# +# BUILD_SHARED_LIBS=OFF ./cmake-testbuild.sh +# + +set -ex + +rm -rf out/include +rm -rf out/lib* +rm -rf out/bin + +if [ -n "$BUILD_SHARED_LIBS" ]; then + bsl=-DBUILD_SHARED_LIBS=$BUILD_SHARED_LIBS +else + bsl=-UBUILD_SHARED_LIBS +fi + +if [ -n "$GLEW_USE_STATIC_LIBS" ]; then + gusl=-DGLEW_USE_STATIC_LIBS=$GLEW_USE_STATIC_LIBS +else + gusl=-UGLEW_USE_STATIC_LIBS +fi + +cmake -Hbuild/cmake -Bout/build/glew -DCMAKE_INSTALL_PREFIX=${PWD}/out -DCMAKE_BUILD_TYPE=Debug $bsl +cmake --build out/build/glew --target install --config Debug +cmake out/build/glew -DCMAKE_BUILD_TYPE=Release +cmake --build out/build/glew --target install --config Release --clean-first + +cmake -Hbuild/cmake/testbuild -Bout/build/cmake-testbuild -DCMAKE_INSTALL_PREFIX=${PWD}/out -DCMAKE_PREFIX_PATH=${PWD}/out -DCMAKE_BUILD_TYPE=Debug $gusl +cmake --build out/build/cmake-testbuild --target install --config Debug + +cmake out/build/cmake-testbuild -DCMAKE_BUILD_TYPE=Release +cmake --build out/build/cmake-testbuild --target install --config Release --clean-first + +export LD_LIBRARY_PATH=${PWD}/out/lib:$LD_LIBRARY_PATH + +out/bin/cmake-test_d +out/bin/cmake-test