Skip to content

Commit

Permalink
Make it possible to call project() in the root CMakeLists.txt (#242)
Browse files Browse the repository at this point in the history
* Make it possible to call project() in the root CMakeLists.txt

This deprecates the use of setup_project() in favor of:

```
set(PROJECT_NAME "MyProject")
set(PROJECT_DESCRIPTION "...")
set(PROJECT_URL "...")
include(cmake/base.cmake)
project(${PROJECT_NAME} CXX)
```

which is going to be CMake friendly from 3.15 onwards

To do so, including cmake/base.cmake will have the following effect:
- setup a script to call after project() is called
- compute PROJECT_VERSION and restore its value after project() is
  called (we cannot use the VERSION argument of project() because we
  compute incompatible version numbers)
- setup a hook to call setup_project_finalize() and optionally
  setup_project_package_finalize()

* [base] Add a link to minimal example if variables are not defined
  • Loading branch information
gergondet committed Oct 9, 2019
1 parent 429af97 commit 192812c
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 133 deletions.
14 changes: 5 additions & 9 deletions .docs/examples/minimal-with-packages.cmake
@@ -1,14 +1,15 @@
# Target-based approach should work from CMake 2.8.12 but it should fully work from 3.1
cmake_minimum_required(VERSION 2.8.12)

include(cmake/base.cmake)

# These variables have to be defined before running SETUP_PROJECT
set(PROJECT_NAME jrl-cmakemodules-minimal-working-example)
set(PROJECT_DESCRIPTION "A project description")
set(PROJECT_URL http://jrl-cmakemodules.readthedocs.io)
set(PROJECT_USE_CMAKE_EXPORT TRUE)

setup_project()
include(cmake/base.cmake)

project(${PROJECT_NAME} CXX)

# Add a required dependency
add_project_dependency(MyDependency REQUIRED)
Expand All @@ -21,9 +22,4 @@ target_link_libraries(myLibrary MyDependency::MyAwesomeLib Boost::timer)

install(TARGETS myLibrary
EXPORT ${TARGETS_EXPORT_NAME}
DESTINATION lib)

# This should be called at the end
SETUP_PROJECT_FINALIZE()
# Needed for the CMake packaging calls
SETUP_PROJECT_PACKAGE_FINALIZE()
DESTINATION lib)
19 changes: 8 additions & 11 deletions .docs/examples/minimal.cmake
@@ -1,16 +1,13 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)

INCLUDE(cmake/base.cmake)
cmake_minimum_required(VERSION 2.8)

# These variables have to be defined before running SETUP_PROJECT
SET(PROJECT_NAME jrl-cmakemodules-minimal-working-example)
SET(PROJECT_DESCRIPTION "A project description")
SET(PROJECT_URL http://jrl-cmakemodules.readthedocs.io)
set(PROJECT_NAME jrl-cmakemodules-minimal-working-example)
set(PROJECT_DESCRIPTION "A project description")
set(PROJECT_URL http://jrl-cmakemodules.readthedocs.io)

SETUP_PROJECT()
include(cmake/base.cmake)

# Configure the build of your project here
# ADD_SUBDIRECTORY(src)
project(${PROJECT_NAME} CXX)

# This should be called at the end
SETUP_PROJECT_FINALIZE()
# Configure the build of your project here
# add_subdirectory(src)
189 changes: 77 additions & 112 deletions base.cmake
Expand Up @@ -74,27 +74,32 @@
# Allows to define a custome extension for C/C++ header files (e.g. .h, .hh, .hpp).
# The default value is set to .hh.
#
# .. variable:: PROJECT_USE_CMAKE_EXPORT
#
# This tells jrl-cmakemodules that you are using export functionalities so it will
# hook the installation of your configuration files. Defaults to false
#

# Please note that functions starting with an underscore are internal
# functions and should not be used directly.

# Include base features.
INCLUDE(cmake/logging.cmake)
INCLUDE(cmake/portability.cmake)
INCLUDE(cmake/compiler.cmake)
INCLUDE(cmake/debian.cmake)
INCLUDE(cmake/dist.cmake)
INCLUDE(cmake/distcheck.cmake)
INCLUDE(cmake/doxygen.cmake)
INCLUDE(cmake/header.cmake)
INCLUDE(cmake/pkg-config.cmake)
INCLUDE(cmake/uninstall.cmake)
INCLUDE(cmake/install-data.cmake)
INCLUDE(cmake/release.cmake)
INCLUDE(cmake/version.cmake)
INCLUDE(cmake/package-config.cmake)
INCLUDE(cmake/version-script.cmake)
INCLUDE(cmake/test.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/logging.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/portability.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/compiler.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/debian.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/dist.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/distcheck.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/doxygen.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/header.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/pkg-config.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/uninstall.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/install-data.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/release.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/version.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/package-config.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/version-script.cmake)
INCLUDE(${CMAKE_CURRENT_LIST_DIR}/test.cmake)

# --------- #
# Constants #
Expand All @@ -103,6 +108,58 @@ INCLUDE(cmake/test.cmake)
# Variables requires by SETUP_PROJECT.
SET(REQUIRED_VARIABLES PROJECT_NAME PROJECT_DESCRIPTION PROJECT_URL)

# Check that required variables are defined.
FOREACH(VARIABLE ${REQUIRED_VARIABLES})
IF (NOT DEFINED ${VARIABLE})
MESSAGE(AUTHOR_WARNING "Required variable ``${VARIABLE}'' has not been defined, perhaps you are including cmake/base.cmake too early")
MESSAGE(AUTHOR_WARNING "Check out https://jrl-cmakemodules.readthedocs.io/en/master/pages/base.html#minimal-working-example for an example")
MESSAGE(FATAL_ERROR "Required variable ``${VARIABLE}'' has not been defined.")
ENDIF(NOT DEFINED ${VARIABLE})
ENDFOREACH(VARIABLE)

INCLUDE(${CMAKE_CURRENT_LIST_DIR}/GNUInstallDirs.cmake)
SET(CMAKE_INSTALL_FULL_PKGLIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}/${PROJECT_NAME})
SET(CMAKE_INSTALL_PKGLIBDIR ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME})

# If the project version number is not set, compute it automatically.
IF(NOT DEFINED PROJECT_VERSION)
VERSION_COMPUTE()
ELSE()
IF(NOT DEFINED PROJECT_VERSION_MAJOR AND
NOT DEFINED PROJECT_VERSION_MINOR AND
NOT DEFINED PROJECT_VERSION_PATCH)
SPLIT_VERSION_NUMBER(${PROJECT_VERSION}
PROJECT_VERSION_MAJOR
PROJECT_VERSION_MINOR
PROJECT_VERSION_PATCH)
ENDIF()
ENDIF()
SET(SAVED_PROJECT_VERSION "${PROJECT_VERSION}")
SET(SAVED_PROJECT_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
SET(SAVED_PROJECT_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
SET(SAVED_PROJECT_VERSION_PATCH "${PROJECT_VERSION_PATCH}")

IF(PROJECT_VERSION MATCHES UNKNOWN)
SET(PROJECT_VERSION_FULL "")
ELSE(PROJECT_VERSION MATCHES UNKNOWN)
SET(PROJECT_VERSION_FULL "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
ENDIF(PROJECT_VERSION MATCHES UNKNOWN)

# Set a script to run after project called
SET(CMAKE_PROJECT_${PROJECT_NAME}_INCLUDE "${CMAKE_CURRENT_LIST_DIR}/post-project.cmake")

# Set a hook to finalize the setup, CMake will set CMAKE_CURRENT_LIST_DIR to "" at the end
# Based off https://stackoverflow.com/questions/15760580/execute-command-or-macro-in-cmake-as-the-last-step-before-the-configure-step-f
VARIABLE_WATCH(CMAKE_CURRENT_LIST_DIR SETUP_PROJECT_FINALIZE_HOOK)
FUNCTION(SETUP_PROJECT_FINALIZE_HOOK VARIABLE ACCESS)
IF("${${VARIABLE}}" STREQUAL "")
SETUP_PROJECT_FINALIZE()
IF(PROJECT_USE_CMAKE_EXPORT)
SETUP_PROJECT_PACKAGE_FINALIZE()
ENDIF()
ENDIF()
ENDFUNCTION()

# --------------------- #
# Project configuration #
# --------------------- #
Expand Down Expand Up @@ -155,103 +212,11 @@ ENDMACRO(_CONCATENATE_ARGUMENTS OUTPUT)
# file).
#
MACRO(SETUP_PROJECT)
INCLUDE(cmake/GNUInstallDirs.cmake)
SET(CMAKE_INSTALL_FULL_PKGLIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}/${PROJECT_NAME})
SET(CMAKE_INSTALL_PKGLIBDIR ${CMAKE_INSTALL_LIBDIR}/${PROJECT_NAME})

# Check that required variables are defined.
FOREACH(VARIABLE ${REQUIRED_VARIABLES})
IF (NOT DEFINED ${VARIABLE})
MESSAGE(FATAL_ERROR
"Required variable ``${VARIABLE}'' has not been defined.")
ENDIF(NOT DEFINED ${VARIABLE})
ENDFOREACH(VARIABLE)

# If the project version number is not set, compute it automatically.
IF(NOT DEFINED PROJECT_VERSION)
VERSION_COMPUTE()
ELSE()
IF(NOT DEFINED PROJECT_VERSION_MAJOR AND
NOT DEFINED PROJECT_VERSION_MINOR AND
NOT DEFINED PROJECT_VERSION_PATCH)
SPLIT_VERSION_NUMBER(${PROJECT_VERSION}
PROJECT_VERSION_MAJOR
PROJECT_VERSION_MINOR
PROJECT_VERSION_PATCH)
ENDIF()
# Define project name.
PROJECT(${PROJECT_NAME} CXX)
IF(${CMAKE_VERSION} VERSION_GREATER 3.15)
MESSAGE("Please update your CMakeLists: instead of setup_project() simply call project(\${PROJECT_NAME} CXX) after including cmake/base.cmake\nYou can also remove setup_project_finalize() call")
ENDIF()

IF(PROJECT_VERSION MATCHES UNKNOWN)
SET(PROJECT_VERSION_FULL "")
ELSE(PROJECT_VERSION MATCHES UNKNOWN)
SET(PROJECT_VERSION_FULL "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
ENDIF(PROJECT_VERSION MATCHES UNKNOWN)

# Define project
IF(${CMAKE_VERSION} VERSION_GREATER 3.0.0)
# Remove warnings or errors
IF(POLICY CMP0048)
CMAKE_POLICY(SET CMP0048 NEW)
ENDIF(POLICY CMP0048)

IF(${CMAKE_VERSION} VERSION_GREATER 3.9.0)
PROJECT(${PROJECT_NAME} LANGUAGES CXX DESCRIPTION ${PROJECT_DESCRIPTION} VERSION ${PROJECT_VERSION_FULL})
ELSE(NOT ${CMAKE_VERSION} VERSION_GREATER 3.9.0)
PROJECT(${PROJECT_NAME} LANGUAGES CXX VERSION ${PROJECT_VERSION_FULL})
ENDIF(${CMAKE_VERSION} VERSION_GREATER 3.9.0)
ELSE(${CMAKE_VERSION} VERSION_GREATER 3.0.0)
PROJECT(${PROJECT_NAME} CXX)
ENDIF(${CMAKE_VERSION} VERSION_GREATER 3.0.0)

IF(DEFINED PROJECT_DEBUG_POSTFIX)
SET(CMAKE_DEBUG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
STRING(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type)
IF(${cmake_build_type} MATCHES debug)
SET(PKGCONFIG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
ELSE()
SET(PKGCONFIG_POSTFIX "")
ENDIF()
IF(DEFINED CMAKE_CONFIGURATION_TYPES)
SET(PKGCONFIG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
ENDIF()
ENDIF()

IF(NOT DEFINED PROJECT_USE_KEYWORD_LINK_LIBRARIES)
SET(PROJECT_USE_KEYWORD_LINK_LIBRARIES FALSE)
ENDIF()
IF(${PROJECT_USE_KEYWORD_LINK_LIBRARIES})
SET(PUBLIC_KEYWORD PUBLIC)
ELSE()
SET(PUBLIC_KEYWORD "")
ENDIF()

IF(${ARGC})
SET(CMAKE_VERBOSE_MAKEFILE ${ARGV0})
ELSE(${ARGC})
# Be verbose by default.
SET(CMAKE_VERBOSE_MAKEFILE TRUE)
ENDIF(${ARGC})

OPTION(INSTALL_DOCUMENTATION "Generate and install the documentation" ON)
OPTION(INSTALL_GENERATED_HEADERS "Generate and install standard headers" ON)
OPTION(INSTALL_PKG_CONFIG_FILE "Generate and install standard .pc file" ON)

INCLUDE(CTest)
ENABLE_TESTING()

LOGGING_INITIALIZE()

#FIXME: normalize naming to <MODULE>_SETUP()
_SETUP_PROJECT_WARNINGS()
_SETUP_PROJECT_HEADER()
_SETUP_PROJECT_DIST()
DISTCHECK_SETUP()
RELEASE_SETUP()
_SETUP_PROJECT_DEB()
_SETUP_PROJECT_UNINSTALL()
_SETUP_PROJECT_PKG_CONFIG()
_SETUP_PROJECT_DOCUMENTATION()
_SETUP_PROJECT_PACKAGE_INIT()
ENDMACRO(SETUP_PROJECT)

#.rst:
Expand Down
1 change: 0 additions & 1 deletion package-config.cmake
Expand Up @@ -84,7 +84,6 @@ ENDMACRO()
# assumes SETUP_PROJECT() was called
# internally the real requirement is that _SETUP_PROJECT_PACKAGE_INIT() was called
MACRO(SETUP_PROJECT_PACKAGE_FINALIZE)

####
# Installation (https://github.com/forexample/package-example)

Expand Down
55 changes: 55 additions & 0 deletions post-project.cmake
@@ -0,0 +1,55 @@
# Restore version information that might have been overriden by project() call
SET(PROJECT_VERSION "${SAVED_PROJECT_VERSION}")
SET(PROJECT_VERSION_MAJOR "${SAVED_PROJECT_VERSION_MAJOR}")
SET(PROJECT_VERSION_MINOR "${SAVED_PROJECT_VERSION_MINOR}")
SET(PROJECT_VERSION_PATCH "${SAVED_PROJECT_VERSION_PATCH}")

IF(DEFINED PROJECT_DEBUG_POSTFIX)
SET(CMAKE_DEBUG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
STRING(TOLOWER "${CMAKE_BUILD_TYPE}" cmake_build_type)
IF(${cmake_build_type} MATCHES debug)
SET(PKGCONFIG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
ELSE()
SET(PKGCONFIG_POSTFIX "")
ENDIF()
IF(DEFINED CMAKE_CONFIGURATION_TYPES)
SET(PKGCONFIG_POSTFIX ${PROJECT_DEBUG_POSTFIX})
ENDIF()
ENDIF()

IF(NOT DEFINED PROJECT_USE_KEYWORD_LINK_LIBRARIES)
SET(PROJECT_USE_KEYWORD_LINK_LIBRARIES FALSE)
ENDIF()
IF(${PROJECT_USE_KEYWORD_LINK_LIBRARIES})
SET(PUBLIC_KEYWORD PUBLIC)
ELSE()
SET(PUBLIC_KEYWORD "")
ENDIF()

IF(${ARGC})
SET(CMAKE_VERBOSE_MAKEFILE ${ARGV0})
ELSE(${ARGC})
# Be verbose by default.
SET(CMAKE_VERBOSE_MAKEFILE TRUE)
ENDIF(${ARGC})

OPTION(INSTALL_DOCUMENTATION "Generate and install the documentation" ON)
OPTION(INSTALL_GENERATED_HEADERS "Generate and install standard headers" ON)
OPTION(INSTALL_PKG_CONFIG_FILE "Generate and install standard .pc file" ON)

INCLUDE(CTest)
ENABLE_TESTING()

LOGGING_INITIALIZE()

#FIXME: normalize naming to <MODULE>_SETUP()
_SETUP_PROJECT_WARNINGS()
_SETUP_PROJECT_HEADER()
_SETUP_PROJECT_DIST()
DISTCHECK_SETUP()
RELEASE_SETUP()
_SETUP_PROJECT_DEB()
_SETUP_PROJECT_UNINSTALL()
_SETUP_PROJECT_PKG_CONFIG()
_SETUP_PROJECT_DOCUMENTATION()
_SETUP_PROJECT_PACKAGE_INIT()
4 changes: 4 additions & 0 deletions version.cmake
Expand Up @@ -56,6 +56,10 @@
MACRO(VERSION_COMPUTE)
SET(PROJECT_STABLE False)

IF("${PROJECT_SOURCE_DIR}" STREQUAL "")
SET(PROJECT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/..")
ENDIF()

# Check if a version is embedded in the project.
IF(EXISTS ${PROJECT_SOURCE_DIR}/.version)
# Yes, use it. This is a stable version.
Expand Down

0 comments on commit 192812c

Please sign in to comment.