diff options
157 files changed, 4694 insertions, 999 deletions
diff --git a/CTestCustom.cmake.in b/CTestCustom.cmake.in index 9eee655..9829191 100644 --- a/CTestCustom.cmake.in +++ b/CTestCustom.cmake.in @@ -40,8 +40,9 @@ SET(CTEST_CUSTOM_WARNING_EXCEPTION "warning.*directory name.*CMake-Xcode.*/bin/.*does not exist.*" "stl_deque.h:1051" "(Lexer|Parser).*warning.*conversion.*may (alter its value|change the sign)" + "(Lexer|Parser).*warning.*statement is unreachable" + "PGC-W-0095-Type cast required for this conversion.*ProcessUNIX.c" "[Qq]t([Cc]ore|[Gg]ui).*warning.*conversion.*may alter its value" - "Parser.cxx.*warning.*2111-D.*statement is unreachable" "warning:.*is.*very unsafe.*consider using.*" "warning:.*is.*misused, please use.*" "CMakeSetupManifest.xml.*manifest authoring warning.*Unrecognized Element" diff --git a/Modules/BasicConfigVersion-ExactVersion.cmake.in b/Modules/BasicConfigVersion-ExactVersion.cmake.in new file mode 100644 index 0000000..c610baa --- /dev/null +++ b/Modules/BasicConfigVersion-ExactVersion.cmake.in @@ -0,0 +1,42 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is equal to the requested version. +# The tweak version component is ignored. +# The variable CVF_VERSION must be set before calling configure_file(). + + +set(PACKAGE_VERSION "@CVF_VERSION@") + +if("@CVF_VERSION@" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\..*") # strip the tweak version + set(CVF_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") +else() + set(CVF_VERSION_NO_TWEAK "@CVF_VERSION@") +endif() + +if("${PACKAGE_FIND_VERSION}" MATCHES "^([0-9]+\\.[0-9]+\\.[0-9]+)\\..*") # strip the tweak version + set(REQUESTED_VERSION_NO_TWEAK "${CMAKE_MATCH_1}") +else() + set(REQUESTED_VERSION_NO_TWEAK "${PACKAGE_FIND_VERSION}") +endif() + +if("${REQUESTED_VERSION_NO_TWEAK}" STREQUAL "${CVF_VERSION_NO_TWEAK}") + set(PACKAGE_VERSION_COMPATIBLE TRUE) +else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) +endif() + +if( "${PACKAGE_FIND_VERSION}" STREQUAL "${PACKAGE_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) +endif() + + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT "${CMAKE_SIZEOF_VOID_P}" STREQUAL "@CMAKE_SIZEOF_VOID_P@") + math(EXPR installedBits "@CMAKE_SIZEOF_VOID_P@ * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/Modules/CMakeGenericSystem.cmake b/Modules/CMakeGenericSystem.cmake index 6cd8fe6..ee8040e 100644 --- a/Modules/CMakeGenericSystem.cmake +++ b/Modules/CMakeGenericSystem.cmake @@ -39,6 +39,8 @@ SET_PROPERTY(GLOBAL PROPERTY TARGET_SUPPORTS_SHARED_LIBS TRUE) SET (CMAKE_SKIP_RPATH "NO" CACHE BOOL "If set, runtime paths are not added when using shared libraries.") +SET (CMAKE_SKIP_INSTALL_RPATH "NO" CACHE BOOL + "If set, runtime paths are not added when installing shared libraries, but are added when building.") SET(CMAKE_VERBOSE_MAKEFILE FALSE CACHE BOOL "If this value is on, makefiles will be generated without the .SILENT directive, and all commands will be echoed to the console during the make. This is useful for debugging only. With Visual Studio IDE projects all commands are done without /nologo.") @@ -168,5 +170,6 @@ ENDIF(CMAKE_HOST_UNIX) MARK_AS_ADVANCED( CMAKE_SKIP_RPATH + CMAKE_SKIP_INSTALL_RPATH CMAKE_VERBOSE_MAKEFILE ) diff --git a/Modules/CMakeNinjaFindMake.cmake b/Modules/CMakeNinjaFindMake.cmake new file mode 100644 index 0000000..f15c3e0 --- /dev/null +++ b/Modules/CMakeNinjaFindMake.cmake @@ -0,0 +1,17 @@ + +#============================================================================= +# Copyright 2011 Kitware, Inc. +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +FIND_PROGRAM(CMAKE_MAKE_PROGRAM ninja + DOC "Program used to build from build.ninja files.") +MARK_AS_ADVANCED(CMAKE_MAKE_PROGRAM) diff --git a/Modules/CMakePackageConfigHelpers.cmake b/Modules/CMakePackageConfigHelpers.cmake new file mode 100644 index 0000000..98cd560 --- /dev/null +++ b/Modules/CMakePackageConfigHelpers.cmake @@ -0,0 +1,197 @@ +# - CONFIGURE_PACKAGE_CONFIG_FILE(), WRITE_BASIC_PACKAGE_VERSION_FILE() +# +# CONFIGURE_PACKAGE_CONFIG_FILE(<input> <output> INSTALL_DESTINATION <path> +# [PATH_VARS <var1> <var2> ... <varN>] +# [NO_SET_AND_CHECK_MACRO] ) +# +# CONFIGURE_PACKAGE_CONFIG_FILE() should be used instead of the plain +# CONFIGURE_FILE() command when creating the <Name>Config.cmake or <Name>-config.cmake +# file for installing a project or library. It helps making the resulting package +# relocatable by avoiding hardcoded paths in the installed Config.cmake file. +# +# In a FooConfig.cmake file there may be code like this to make the +# install destinations know to the using project: +# set(FOO_INCLUDE_DIR "@CMAKE_INSTALL_FULL_INCLUDEDIR@" ) +# set(FOO_DATA_DIR "@CMAKE_INSTALL_PREFIX@/@RELATIVE_DATA_INSTALL_DIR@" ) +# set(FOO_ICONS_DIR "@CMAKE_INSTALL_PREFIX@/share/icons" ) +# ...logic to determine installedPrefix from the own location... +# set(FOO_CONFIG_DIR "${installedPrefix}/@CONFIG_INSTALL_DIR@" ) +# All 4 options shown above are not sufficient, since the first 3 hardcode +# the absolute directory locations, and the 4th case works only if the logic +# to determine the installedPrefix is correct, and if CONFIG_INSTALL_DIR contains +# a relative path, which in general cannot be guaranteed. +# This has the effect that the resulting FooConfig.cmake file would work poorly +# under Windows and OSX, where users are used to choose the install location +# of a binary package at install time, independent from how CMAKE_INSTALL_PREFIX +# was set at build/cmake time. +# +# Using CONFIGURE_PACKAGE_CONFIG_FILE() helps. If used correctly, it makes the +# resulting FooConfig.cmake file relocatable. +# Usage: +# 1. write a FooConfig.cmake.in file as you are used to +# 2. insert a line containing only the string "@PACKAGE_INIT@" +# 3. instead of SET(FOO_DIR "@SOME_INSTALL_DIR@"), use SET(FOO_DIR "@PACKAGE_SOME_INSTALL_DIR@") +# (this must be after the @PACKAGE_INIT@ line) +# 4. instead of using the normal CONFIGURE_FILE(), use CONFIGURE_PACKAGE_CONFIG_FILE() +# +# The <input> and <output> arguments are the input and output file, the same way +# as in CONFIGURE_FILE(). +# +# The <path> given to INSTALL_DESTINATION must be the destination where the FooConfig.cmake +# file will be installed to. This can either be a relative or absolute path, both work. +# +# The variables <var1> to <varN> given as PATH_VARS are the variables which contain +# install destinations. For each of them the macro will create a helper variable +# PACKAGE_<var...>. These helper variables must be used +# in the FooConfig.cmake.in file for setting the installed location. They are calculated +# by CONFIGURE_PACKAGE_CONFIG_FILE() so that they are always relative to the +# installed location of the package. This works both for relative and also for absolute locations. +# For absolute locations it works only if the absolute location is a subdirectory +# of CMAKE_INSTALL_PREFIX. +# +# By default configure_package_config_file() also generates a macro set_and_check() +# into the FooConfig.cmake file. This should be used instead of the normal set() +# command for setting directories and file locations. Additionally to setting the +# variable it also checks that the referenced file or directory actually exists +# and fails with a FATAL_ERROR otherwise. This makes sure that the created +# FooConfig.cmake file does not contain wrong references. +# When using the NO_SET_AND_CHECK_MACRO, this macro is not generated into the +# FooConfig.cmake file. +# +# For an example see below the documentation for WRITE_BASIC_PACKAGE_VERSION_FILE(). +# +# +# WRITE_BASIC_PACKAGE_VERSION_FILE( filename VERSION major.minor.patch COMPATIBILITY (AnyNewerVersion|SameMajorVersion|ExactVersion) ) +# +# Writes a file for use as <package>ConfigVersion.cmake file to <filename>. +# See the documentation of FIND_PACKAGE() for details on this. +# filename is the output filename, it should be in the build tree. +# major.minor.patch is the version number of the project to be installed +# The COMPATIBILITY mode AnyNewerVersion means that the installed package version +# will be considered compatible if it is newer or exactly the same as the requested version. +# This mode should be used for packages which are fully backward compatible, +# also across major versions. +# If SameMajorVersion is used instead, then the behaviour differs from AnyNewerVersion +# in that the major version number must be the same as requested, e.g. version 2.0 will +# not be considered compatible if 1.0 is requested. +# This mode should be used for packages which guarantee backward compatibility within the +# same major version. +# If ExactVersion is used, then the package is only considered compatible if the requested +# version matches exactly its own version number (not considering the tweak version). +# For example, version 1.2.3 of a package is only considered compatible to requested version 1.2.3. +# This mode is for packages without compatibility guarantees. +# If your project has more elaborated version matching rules, you will need to write your +# own custom ConfigVersion.cmake file instead of using this macro. +# +# Internally, this macro executes configure_file() to create the resulting +# version file. Depending on the COMPATIBLITY, either the file +# BasicConfigVersion-SameMajorVersion.cmake.in or BasicConfigVersion-AnyNewerVersion.cmake.in +# is used. Please note that these two files are internal to CMake and you should +# not call configure_file() on them yourself, but they can be used as starting +# point to create more sophisticted custom ConfigVersion.cmake files. +# +# +# Example using both configure_package_config_file() and write_basic_package_version_file(): +# CMakeLists.txt: +# set(INCLUDE_INSTALL_DIR include/ ... CACHE ) +# set(LIB_INSTALL_DIR lib/ ... CACHE ) +# set(SYSCONFIG_INSTALL_DIR etc/foo/ ... CACHE ) +# ... +# include(CMakePackageConfigHelpers) +# configure_package_config_file(FooConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake +# INSTALL_DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake +# PATH_VARS INCLUDE_INSTALL_DIR SYSCONFIG_INSTALL_DIR) +# write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake +# VERSION 1.2.3 +# COMPATIBILITY SameMajorVersion ) +# install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake +# DESTINATION ${LIB_INSTALL_DIR}/Foo/cmake ) +# +# With a FooConfig.cmake.in: +# set(FOO_VERSION x.y.z) +# ... +# @PACKAGE_INIT@ +# ... +# set_and_check(FOO_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +# set_and_check(FOO_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@") + + +#============================================================================= +# Copyright 2012 Alexander Neundorf <neundorf@kde.org> +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +include(CMakeParseArguments) + +include(WriteBasicConfigVersionFile) + +macro(WRITE_BASIC_PACKAGE_VERSION_FILE) + write_basic_config_version_file(${ARGN}) +endmacro() + + +function(CONFIGURE_PACKAGE_CONFIG_FILE _inputFile _outputFile) + set(options NO_SET_AND_CHECK_MACRO) + set(oneValueArgs INSTALL_DESTINATION ) + set(multiValueArgs PATH_VARS ) + + cmake_parse_arguments(CCF "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(CCF_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to CONFIGURE_PACKAGE_CONFIG_FILE(): \"${CCF_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT CCF_INSTALL_DESTINATION) + message(FATAL_ERROR "No INSTALL_DESTINATION given to CONFIGURE_PACKAGE_CONFIG_FILE()") + endif() + + if(IS_ABSOLUTE "${CCF_INSTALL_DESTINATION}") + set(absInstallDir "${CCF_INSTALL_DESTINATION}") + else() + set(absInstallDir "${CMAKE_INSTALL_PREFIX}/${CCF_INSTALL_DESTINATION}") + endif() + file(RELATIVE_PATH PACKAGE_RELATIVE_PATH "${absInstallDir}" "${CMAKE_INSTALL_PREFIX}" ) + + foreach(var ${CCF_PATH_VARS}) + if(NOT DEFINED ${var}) + message(FATAL_ERROR "Variable ${var} does not exist") + else() + if(IS_ABSOLUTE "${${var}}") + string(REPLACE "${CMAKE_INSTALL_PREFIX}" "\${PACKAGE_PREFIX_DIR}" + PACKAGE_${var} "${${var}}") + else() + set(PACKAGE_${var} "\${PACKAGE_PREFIX_DIR}/${${var}}") + endif() + endif() + endforeach() + + set(PACKAGE_INIT " +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +get_filename_component(PACKAGE_PREFIX_DIR \"\${CMAKE_CURRENT_LIST_DIR}/${PACKAGE_RELATIVE_PATH}\" ABSOLUTE) +") + + if(NOT CCF_NO_SET_AND_CHECK_MACRO) + set(PACKAGE_INIT "${PACKAGE_INIT} +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() +") + endif() + + set(PACKAGE_INIT "${PACKAGE_INIT} +####################################################################################") + + configure_file("${_inputFile}" "${_outputFile}" @ONLY) + +endfunction() diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index b506711..571770e 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -101,6 +101,11 @@ ##end # ##variable +# CPACK_PACKAGE_ICON - A branding image that will be displayed inside +# the installer (used by GUI installers). +##end +# +##variable # CPACK_PROJECT_CONFIG_FILE - CPack-time project CPack configuration # file. This file included at cpack time, once per # generator after CPack has set CPACK_GENERATOR to the actual generator @@ -247,6 +252,15 @@ # CPACK_INSTALLED_DIRECTORIES - Extra directories to install. ##end # +##variable +# CPACK_PACKAGE_INSTALL_REGISTRY_KEY - Registry key used when +# installing this project. This is only used +# by installer for Windows. +##end +##variable +# CPACK_CREATE_DESKTOP_LINKS - List of desktop links to create. +##end +# #============================================================================= # Copyright 2006-2009 Kitware, Inc. diff --git a/Modules/CPackNSIS.cmake b/Modules/CPackNSIS.cmake index 97179d7..7d9f29b 100644 --- a/Modules/CPackNSIS.cmake +++ b/Modules/CPackNSIS.cmake @@ -8,11 +8,6 @@ ##end # ##variable -# CPACK_PACKAGE_INSTALL_REGISTRY_KEY - Registry key used when -# installing this project. -##end -# -##variable # CPACK_NSIS_INSTALL_ROOT - The default installation directory presented # to the end user by the NSIS installer is under this root dir. The full # directory presented to the end user is: @@ -30,11 +25,6 @@ ##end # ##variable -# CPACK_PACKAGE_ICON - A branding image that will be displayed inside -# the installer. -##end -# -##variable # CPACK_NSIS_EXTRA_INSTALL_COMMANDS - Extra NSIS commands that will # be added to the install Section. ##end @@ -107,6 +97,15 @@ # CPACK_NSIS_MUI_FINISHPAGE_RUN - Specify an executable to add an option # to run on the finish page of the NSIS installer. ##end +##variable +# CPACK_NSIS_MENU_LINKS - Specify links in [application] menu. +# This should contain a list of pair "link" "link name". The link +# may be an URL or a path relative to installation prefix. +# Like: +# set(CPACK_NSIS_MENU_LINKS +# "doc/cmake-@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@/cmake.html" "CMake Help" +# "http://www.cmake.org" "CMake Web Site") +##end #============================================================================= # Copyright 2006-2009 Kitware, Inc. diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake index 8d6f5df..bdcaf9d 100644 --- a/Modules/Compiler/GNU.cmake +++ b/Modules/Compiler/GNU.cmake @@ -24,6 +24,15 @@ macro(__compiler_gnu lang) set(CMAKE_SHARED_LIBRARY_${lang}_FLAGS "-fPIC") set(CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS "-shared") + # Older versions of gcc (< 4.5) contain a bug causing them to report a missing + # header file as a warning if depfiles are enabled, causing check_header_file + # tests to always succeed. Work around this by disabling dependency tracking + # in try_compile mode. + GET_PROPERTY(_IN_TC GLOBAL PROPERTY IN_TRY_COMPILE) + if(NOT _IN_TC OR CMAKE_FORCE_DEPFILES) + set(CMAKE_DEPFILE_FLAGS_${lang} "-MMD -MF <DEPFILE>") + endif() + # Initial configuration flags. set(CMAKE_${lang}_FLAGS_INIT "") set(CMAKE_${lang}_FLAGS_DEBUG_INIT "-g") diff --git a/Modules/DeployQt4.cmake b/Modules/DeployQt4.cmake index 83f322c..b37695d 100644 --- a/Modules/DeployQt4.cmake +++ b/Modules/DeployQt4.cmake @@ -82,6 +82,7 @@ include(BundleUtilities) set(DeployQt4_cmake_dir "${CMAKE_CURRENT_LIST_DIR}") +set(DeployQt4_apple_plugins_dir "PlugIns") function(write_qt4_conf qt_conf_dir qt_conf_contents) set(qt_conf_path "${qt_conf_dir}/qt.conf") @@ -125,11 +126,17 @@ function(fixup_qt4_executable executable) if(QT_LIBRARY_DIR) list(APPEND dirs "${QT_LIBRARY_DIR}") endif() + if(QT_BINARY_DIR) + list(APPEND dirs "${QT_BINARY_DIR}") + endif() if(APPLE) set(qt_conf_dir "${executable}/Contents/Resources") set(executable_path "${executable}") set(write_qt_conf TRUE) + if(NOT plugins_dir) + set(plugins_dir "${DeployQt4_apple_plugins_dir}") + endif() else() get_filename_component(executable_path "${executable}" PATH) if(NOT executable_path) @@ -141,7 +148,7 @@ function(fixup_qt4_executable executable) foreach(plugin ${qtplugins}) set(installed_plugin_path "") - install_qt4_plugin("${plugin}" "${plugins_dir}" "${executable}" 1 installed_plugin_path) + install_qt4_plugin("${plugin}" "${executable}" 1 installed_plugin_path) list(APPEND libs ${installed_plugin_path}) endforeach() @@ -166,23 +173,19 @@ function(install_qt4_plugin_path plugin executable copy installed_plugin_path_va set(component ${ARGV5}) set(configurations ${ARGV6}) if(EXISTS "${plugin}") - if(plugins_dir) - set(plugins_dir "${plugins_dir}") - else() - if(APPLE) - set(plugins_dir "PlugIns") - else() - set(plugins_dir "plugins") - endif() - endif() if(APPLE) + if(NOT plugins_dir) + set(plugins_dir "${DeployQt4_apple_plugins_dir}") + endif() set(plugins_path "${executable}/Contents/${plugins_dir}") else() - get_filename_component(executable_path "${executable}" PATH) - if(NOT executable_path) - set(executable_path ".") + get_filename_component(plugins_path "${executable}" PATH) + if(NOT plugins_path) + set(plugins_path ".") + endif() + if(plugins_dir) + set(plugins_path "${plugins_path}/${plugins_dir}") endif() - set(plugins_path "${executable_path}/${plugins_dir}") endif() set(plugin_group "") @@ -210,7 +213,7 @@ function(install_qt4_plugin_path plugin executable copy installed_plugin_path_va endif() install(FILES "${plugin}" DESTINATION "${plugins_path}" ${configurations} ${component}) endif() - set(${installed_plugin_path_var} ${${installed_path_var}} "${plugins_path}/${plugin_name}" PARENT_SCOPE) + set(${installed_plugin_path_var} "${plugins_path}/${plugin_name}" PARENT_SCOPE) endif() endfunction() @@ -220,11 +223,7 @@ function(install_qt4_plugin plugin executable copy installed_plugin_path_var) if(EXISTS "${plugin}") install_qt4_plugin_path("${plugin}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}") else() - if(QT_IS_STATIC) - string(TOUPPER "QT_${plugin}_LIBRARY" plugin_var) - else() - string(TOUPPER "QT_${plugin}_PLUGIN" plugin_var) - endif() + string(TOUPPER "QT_${plugin}_PLUGIN" plugin_var) set(plugin_release_var "${plugin_var}_RELEASE") set(plugin_debug_var "${plugin_var}_DEBUG") set(plugin_release "${${plugin_release_var}}") @@ -232,10 +231,24 @@ function(install_qt4_plugin plugin executable copy installed_plugin_path_var) if(DEFINED "${plugin_release_var}" AND DEFINED "${plugin_debug_var}" AND NOT EXISTS "${plugin_release}" AND NOT EXISTS "${plugin_debug}") message(WARNING "Qt plugin \"${plugin}\" not recognized or found.") endif() - install_qt4_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}" "Release|RelWithDebInfo|MinSizeRel") - install_qt4_plugin_path("${plugin_debug}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}" "Debug") + if(NOT EXISTS "${${plugin_debug_var}}") + set(plugin_debug "${plugin_release}") + endif() + + if(CMAKE_CONFIGURATION_TYPES OR CMAKE_BUILD_TYPE) + install_qt4_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}_release" "${plugins_dir}" "${component}" "Release|RelWithDebInfo|MinSizeRel") + install_qt4_plugin_path("${plugin_debug}" "${executable}" "${copy}" "${installed_plugin_path_var}_debug" "${plugins_dir}" "${component}" "Debug") + + if(CMAKE_BUILD_TYPE MATCHES "^Debug$") + set(${installed_plugin_path_var} ${${installed_plugin_path_var}_debug}) + else() + set(${installed_plugin_path_var} ${${installed_plugin_path_var}_release}) + endif() + else() + install_qt4_plugin_path("${plugin_release}" "${executable}" "${copy}" "${installed_plugin_path_var}" "${plugins_dir}" "${component}") + endif() endif() - set(installed_plugin_path_var "${installed_plugin_path_var}" PARENT_SCOPE) + set(${installed_plugin_path_var} ${${installed_plugin_path_var}} PARENT_SCOPE) endfunction() function(install_qt4_executable executable) @@ -248,6 +261,9 @@ function(install_qt4_executable executable) if(QT_LIBRARY_DIR) list(APPEND dirs "${QT_LIBRARY_DIR}") endif() + if(QT_BINARY_DIR) + list(APPEND dirs "${QT_BINARY_DIR}") + endif() if(component) set(component COMPONENT ${component}) else() @@ -264,16 +280,16 @@ function(install_qt4_executable executable) set(qt_plugins_dir "") endif() - if(NOT qtplugins AND QT_LIBRARIES_PLUGINS) - set(qtplugins "${QT_LIBRARIES_PLUGINS}") + if(QT_IS_STATIC) + message(WARNING "Qt built statically: not installing plugins.") + else() + foreach(plugin ${qtplugins}) + set(installed_plugin_paths "") + install_qt4_plugin("${plugin}" "${executable}" 0 installed_plugin_paths "${plugins_dir}" "${component}") + list(APPEND libs ${installed_plugin_paths}) + endforeach() endif() - foreach(plugin ${qtplugins}) - set(installed_plugin_paths "") - install_qt4_plugin("${plugin}" "${executable}" 0 installed_plugin_paths "${plugins_dir}" "${component}") - list(APPEND libs ${installed_plugin_paths}) - endforeach() - resolve_qt4_paths(libs) install(CODE diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index fb55d3b..b6fe190 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -833,6 +833,12 @@ function(ExternalProject_Add_StepTargets name) foreach(step ${steps}) add_custom_target(${name}-${step} DEPENDS ${stamp_dir}${cfgdir}/${name}-${step}) + + # Depend on other external projects (target-level). + get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS) + foreach(arg IN LISTS deps) + add_dependencies(${name}-${step} ${arg}) + endforeach() endforeach() endfunction(ExternalProject_Add_StepTargets) @@ -1451,9 +1457,18 @@ function(ExternalProject_Add name) # depends on the 'done' mark so that it rebuilds when this project # rebuilds. It is important that 'done' is not the output of any # custom command so that CMake does not propagate build rules to - # other external project targets. + # other external project targets, which may cause problems during + # parallel builds. However, the Ninja generator needs to see the entire + # dependency graph, and can cope with custom commands belonging to + # multiple targets, so we add the 'done' mark as an output for Ninja only. + set(complete_outputs ${cmf_dir}${cfgdir}/${name}-complete) + if(${CMAKE_GENERATOR} MATCHES "Ninja") + set(complete_outputs + ${complete_outputs} ${stamp_dir}${cfgdir}/${name}-done) + endif() + add_custom_command( - OUTPUT ${cmf_dir}${cfgdir}/${name}-complete + OUTPUT ${complete_outputs} COMMENT "Completed '${name}'" COMMAND ${CMAKE_COMMAND} -E make_directory ${cmf_dir}${cfgdir} COMMAND ${CMAKE_COMMAND} -E touch ${cmf_dir}${cfgdir}/${name}-complete diff --git a/Modules/FindCxxTest.cmake b/Modules/FindCxxTest.cmake index 4ff310c..a4d1504 100644 --- a/Modules/FindCxxTest.cmake +++ b/Modules/FindCxxTest.cmake @@ -9,6 +9,7 @@ # Only used in the case both Python & Perl # are detected on the system to control # which CxxTest code generator is used. +# Valid only for CxxTest version 3. # # NOTE: In older versions of this Find Module, # this variable controlled if the Python test @@ -159,7 +160,8 @@ find_package(PythonInterp QUIET) find_package(Perl QUIET) find_path(CXXTEST_INCLUDE_DIR cxxtest/TestSuite.h) -find_program(CXXTEST_PYTHON_TESTGEN_EXECUTABLE cxxtestgen.py +find_program(CXXTEST_PYTHON_TESTGEN_EXECUTABLE + NAMES cxxtestgen cxxtestgen.py PATHS ${CXXTEST_INCLUDE_DIR}) find_program(CXXTEST_PERL_TESTGEN_EXECUTABLE cxxtestgen.pl PATHS ${CXXTEST_INCLUDE_DIR}) @@ -167,7 +169,7 @@ find_program(CXXTEST_PERL_TESTGEN_EXECUTABLE cxxtestgen.pl if(PYTHONINTERP_FOUND OR PERL_FOUND) include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) - if(PYTHONINTERP_FOUND AND (CXXTEST_USE_PYTHON OR NOT PERL_FOUND)) + if(PYTHONINTERP_FOUND AND (CXXTEST_USE_PYTHON OR NOT PERL_FOUND OR NOT DEFINED CXXTEST_USE_PYTHON)) set(CXXTEST_TESTGEN_EXECUTABLE ${CXXTEST_PYTHON_TESTGEN_EXECUTABLE}) set(CXXTEST_TESTGEN_INTERPRETER ${PYTHON_EXECUTABLE}) FIND_PACKAGE_HANDLE_STANDARD_ARGS(CxxTest DEFAULT_MSG diff --git a/Modules/FindQt3.cmake b/Modules/FindQt3.cmake index 86236cc..2d8dbde 100644 --- a/Modules/FindQt3.cmake +++ b/Modules/FindQt3.cmake @@ -1,10 +1,11 @@ # - Locate Qt include paths and libraries # This module defines: -# QT_INCLUDE_DIR - where to find qt.h, etc. -# QT_LIBRARIES - the libraries to link against to use Qt. -# QT_DEFINITIONS - definitions to use when -# compiling code that uses Qt. -# QT_FOUND - If false, don't try to use Qt. +# QT_INCLUDE_DIR - where to find qt.h, etc. +# QT_LIBRARIES - the libraries to link against to use Qt. +# QT_DEFINITIONS - definitions to use when +# compiling code that uses Qt. +# QT_FOUND - If false, don't try to use Qt. +# QT_VERSION_STRING - the version of Qt found # # If you need the multithreaded version of Qt, set QT_MT_REQUIRED to TRUE # @@ -46,13 +47,16 @@ IF(QT4_FOUND) ENDIF(QT4_FOUND) -FILE(GLOB GLOB_PATHS_BIN /usr/lib/qt-3*/bin/) +FILE(GLOB GLOB_PATHS /usr/lib/qt-3*) +FOREACH(GLOB_PATH ${GLOB_PATHS}) + LIST(APPEND GLOB_PATHS_BIN "${GLOB_PATH}/bin") +ENDFOREACH(GLOB_PATH) FIND_PATH(QT_INCLUDE_DIR qt.h "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.1;InstallDir]/include/Qt" "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.2.0;InstallDir]/include/Qt" "[HKEY_CURRENT_USER\\Software\\Trolltech\\Qt3Versions\\3.1.0;InstallDir]/include/Qt" $ENV{QTDIR}/include - ${GLOB_PATHS_BIN} + ${GLOB_PATHS} /usr/local/qt/include /usr/lib/qt/include /usr/lib/qt3/include @@ -71,12 +75,13 @@ ENDIF(NOT EXISTS ${QT_INCLUDE_DIR}/qglobal.h) IF(QT_INCLUDE_DIR) #extract the version string from qglobal.h FILE(READ ${QT_INCLUDE_DIR}/qglobal.h QGLOBAL_H) - STRING(REGEX MATCH "#define[\t ]+QT_VERSION_STR[\t ]+\"([0-9]+.[0-9]+.[0-9]+)\"" QGLOBAL_H "${QGLOBAL_H}") - STRING(REGEX REPLACE ".*\"([0-9]+.[0-9]+.[0-9]+)\".*" "\\1" qt_version_str "${QGLOBAL_H}") + STRING(REGEX MATCH "#define[\t ]+QT_VERSION_STR[\t ]+\"[0-9]+.[0-9]+.[0-9]+[a-z]*\"" QGLOBAL_H "${QGLOBAL_H}") + STRING(REGEX REPLACE ".*\"([0-9]+.[0-9]+.[0-9]+[a-z]*)\".*" "\\1" qt_version_str "${QGLOBAL_H}") # Under windows the qt library (MSVC) has the format qt-mtXYZ where XYZ is the # version X.Y.Z, so we need to remove the dots from version STRING(REGEX REPLACE "\\." "" qt_version_str_lib "${qt_version_str}") + SET(QT_VERSION_STRING "${qt_version_str}") ENDIF(QT_INCLUDE_DIR) FILE(GLOB GLOB_PATHS_LIB /usr/lib/qt-3*/lib/) @@ -195,58 +200,16 @@ IF (WIN32) ) ENDIF (WIN32) - -IF (QT_MIN_VERSION) - - STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" qt_major_vers "${qt_version_str}") - STRING(REGEX REPLACE "[0-9]+\\.([0-9]+)\\.[0-9]+" "\\1" qt_minor_vers "${qt_version_str}") - STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" qt_patch_vers "${qt_version_str}") - - #now parse the parts of the user given version string into variables - STRING(REGEX MATCH "^[0-9]+\\.[0-9]+\\.[0-9]+$" req_qt_major_vers "${QT_MIN_VERSION}") - IF (NOT req_qt_major_vers) - error_message( "Invalid Qt version string given: \"${QT_MIN_VERSION}\", expected e.g. \"3.1.5\"") - ENDIF (NOT req_qt_major_vers) - - STRING(REGEX REPLACE "([0-9]+)\\.[0-9]+\\.[0-9]+" "\\1" req_qt_major_vers "${QT_MIN_VERSION}") - STRING(REGEX REPLACE "[0-9]+\\.([0-9])+\\.[0-9]+" "\\1" req_qt_minor_vers "${QT_MIN_VERSION}") - STRING(REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+)" "\\1" req_qt_patch_vers "${QT_MIN_VERSION}") - - # req = "6.5.4", qt = "3.2.1" - MACRO(error_message msg) - IF(QT3_REQUIRED) - MESSAGE( FATAL_ERROR ${msg}) - ELSE(QT3_REQUIRED) - MESSAGE( STATUS ${msg}) - ENDIF(QT3_REQUIRED) - ENDMACRO(error_message) - - IF (req_qt_major_vers GREATER qt_major_vers) # (6 > 3) ? - ERROR_MESSAGE( "Qt major version not matched (required: ${QT_MIN_VERSION}, found: ${qt_version_str})") # yes - ELSE (req_qt_major_vers GREATER qt_major_vers) # no - IF (req_qt_major_vers LESS qt_major_vers) # (6 < 3) ? - SET( QT_VERSION_BIG_ENOUGH "YES" ) # yes - ELSE (req_qt_major_vers LESS qt_major_vers) # ( 6==3) ? - IF (req_qt_minor_vers GREATER qt_minor_vers) # (5>2) ? - ERROR_MESSAGE( "Qt minor version not matched (required: ${QT_MIN_VERSION}, found: ${qt_version_str})") # yes - ELSE (req_qt_minor_vers GREATER qt_minor_vers) # no - IF (req_qt_minor_vers LESS qt_minor_vers) # (5<2) ? - SET( QT_VERSION_BIG_ENOUGH "YES" ) # yes - ELSE (req_qt_minor_vers LESS qt_minor_vers) # (5==2) - IF (req_qt_patch_vers GREATER qt_patch_vers) # (4>1) ? - ERROR_MESSAGE( "Qt patch level not matched (required: ${QT_MIN_VERSION}, found: ${qt_version_str})") # yes - ELSE (req_qt_patch_vers GREATER qt_patch_vers) # (4>1) ? - SET( QT_VERSION_BIG_ENOUGH "YES" ) # yes - ENDIF (req_qt_patch_vers GREATER qt_patch_vers) # (4>1) ? - ENDIF (req_qt_minor_vers LESS qt_minor_vers) - ENDIF (req_qt_minor_vers GREATER qt_minor_vers) - ENDIF (req_qt_major_vers LESS qt_major_vers) - ENDIF (req_qt_major_vers GREATER qt_major_vers) -ENDIF (QT_MIN_VERSION) +#support old QT_MIN_VERSION if set, but not if version is supplied by find_package() +IF(NOT Qt3_FIND_VERSION AND QT_MIN_VERSION) + SET(Qt3_FIND_VERSION ${QT_MIN_VERSION}) +ENDIF(NOT Qt3_FIND_VERSION AND QT_MIN_VERSION) # if the include a library are found then we have it INCLUDE(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(Qt3 DEFAULT_MSG QT_QT_LIBRARY QT_INCLUDE_DIR QT_MOC_EXECUTABLE) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(Qt3 + REQUIRED_VARS QT_QT_LIBRARY QT_INCLUDE_DIR QT_MOC_EXECUTABLE + VERSION_VAR QT_VERSION_STRING) SET(QT_FOUND ${QT3_FOUND} ) IF(QT_FOUND) @@ -296,8 +259,16 @@ IF(QT_FOUND) ENDIF(QT_QT_LIBRARY MATCHES "qt-mt") ENDIF(QT_FOUND) -EXEC_PROGRAM(${QT_MOC_EXECUTABLE} ARGS "-v" OUTPUT_VARIABLE QTVERSION_MOC) -EXEC_PROGRAM(${QT_UIC_EXECUTABLE} ARGS "-version" OUTPUT_VARIABLE QTVERSION_UIC) +IF(QT_MOC_EXECUTABLE) + EXECUTE_PROCESS(COMMAND ${QT_MOC_EXECUTABLE} "-v" + OUTPUT_VARIABLE QTVERSION_MOC + ERROR_QUIET) +ENDIF(QT_MOC_EXECUTABLE) +IF(QT_UIC_EXECUTABLE) + EXECUTE_PROCESS(COMMAND ${QT_UIC_EXECUTABLE} "-version" + OUTPUT_VARIABLE QTVERSION_UIC + ERROR_QUIET) +ENDIF(QT_UIC_EXECUTABLE) SET(_QT_UIC_VERSION_3 FALSE) IF("${QTVERSION_UIC}" MATCHES ".* 3..*") diff --git a/Modules/Platform/Windows-cl.cmake b/Modules/Platform/Windows-cl.cmake index ccccbc9..be6abb6 100644 --- a/Modules/Platform/Windows-cl.cmake +++ b/Modules/Platform/Windows-cl.cmake @@ -37,7 +37,7 @@ SET(CMAKE_COMPILE_RESOURCE "rc <FLAGS> /fo<OBJECT> <SOURCE>") # that is automatically copied into try_compile directories # by the global generator. SET(MSVC_IDE 1) -IF(CMAKE_GENERATOR MATCHES "Makefiles") +IF(CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja") SET(MSVC_IDE 0) IF(NOT CMAKE_VC_COMPILER_TESTS_RUN) SET(CMAKE_VC_COMPILER_TESTS 1) @@ -125,7 +125,7 @@ IF(CMAKE_GENERATOR MATCHES "Makefiles") ENDIF(CMAKE_COMPILER_RETURN) MAKE_DIRECTORY("${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp3") ENDIF(NOT CMAKE_VC_COMPILER_TESTS_RUN) -ENDIF(CMAKE_GENERATOR MATCHES "Makefiles") +ENDIF(CMAKE_GENERATOR MATCHES "Makefiles" OR CMAKE_GENERATOR MATCHES "Ninja") IF(MSVC_C_ARCHITECTURE_ID MATCHES 64) SET(CMAKE_CL_64 1) diff --git a/Modules/WriteBasicConfigVersionFile.cmake b/Modules/WriteBasicConfigVersionFile.cmake index 0b6519d..038cb57 100644 --- a/Modules/WriteBasicConfigVersionFile.cmake +++ b/Modules/WriteBasicConfigVersionFile.cmake @@ -1,31 +1,6 @@ # WRITE_BASIC_CONFIG_VERSION_FILE( filename VERSION major.minor.patch COMPATIBILITY (AnyNewerVersion|SameMajorVersion) ) # -# Writes a file for use as <package>ConfigVersion.cmake file to <filename>. -# See the documentation of FIND_PACKAGE() for details on this. -# filename is the output filename, it should be in the build tree. -# major.minor.patch is the version number of the project to be installed -# The COMPATIBILITY mode AnyNewerVersion means that the installed package version -# will be considered compatible if it is newer or exactly the same as the requested version. -# If SameMajorVersion is used instead, then the behaviour differs from AnyNewerVersion -# in that the major version number must be the same as requested, e.g. version 2.0 will -# not be considered compatible if 1.0 is requested. -# If your project has more elaborated version matching rules, you will need to write your -# own custom ConfigVersion.cmake file instead of using this macro. -# -# Example: -# write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake -# VERSION 1.2.3 -# COMPATIBILITY SameMajorVersion ) -# install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FooConfigVersion.cmake -# ${CMAKE_CURRENT_BINARY_DIR}/FooConfig.cmake -# DESTINATION lib/cmake/Foo ) -# -# Internally, this macro executes configure_file() to create the resulting -# version file. Depending on the COMPATIBLITY, either the file -# BasicConfigVersion-SameMajorVersion.cmake.in or BasicConfigVersion-AnyNewerVersion.cmake.in -# is used. Please note that these two files are internal to CMake and you should -# not call configure_file() on them yourself, but they can be used as starting -# point to create more sophisticted custom ConfigVersion.cmake files. +# Deprecated, see WRITE_BASIC_PACKAGE_VERSION_FILE(), it is identical. #============================================================================= # Copyright 2008-2011 Alexander Neundorf, <neundorf@kde.org> diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 0c420b9..18f9b8b 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -353,6 +353,36 @@ IF (WIN32) ENDIF(NOT UNIX) ENDIF (WIN32) +# turn on Ninja by default +set(_CMAKE_DEFAULT_NINJA_VALUE TRUE) +# turn it off for platforms where it does not pass all the +# tests +if(WIN32 OR APPLE) + SET(_CMAKE_DEFAULT_NINJA_VALUE FALSE) +endif() +SET(CMAKE_ENABLE_NINJA ${_CMAKE_DEFAULT_NINJA_VALUE} CACHE BOOL + "Enable the ninja generator for CMake. currently not fully working for Windows or OSX") +MARK_AS_ADVANCED(CMAKE_ENABLE_NINJA) +IF(CMAKE_ENABLE_NINJA) + MESSAGE(STATUS "Enable ninja generator.") + SET(SRCS ${SRCS} + cmGlobalNinjaGenerator.cxx + cmGlobalNinjaGenerator.h + cmNinjaTypes.h + cmLocalNinjaGenerator.cxx + cmLocalNinjaGenerator.h + cmNinjaTargetGenerator.cxx + cmNinjaTargetGenerator.h + cmNinjaNormalTargetGenerator.cxx + cmNinjaNormalTargetGenerator.h + cmNinjaUtilityTargetGenerator.cxx + cmNinjaUtilityTargetGenerator.h + ) + ADD_DEFINITIONS(-DCMAKE_USE_NINJA) +ELSE() + MESSAGE(STATUS "Disable ninja generator.") +ENDIF() + # create a library used by the command line and the GUI ADD_LIBRARY(CMakeLib ${SRCS}) TARGET_LINK_LIBRARIES(CMakeLib cmsys diff --git a/Source/CPack/cmCPackDocumentVariables.cxx b/Source/CPack/cmCPackDocumentVariables.cxx index 23e99f8..d2e3802 100644 --- a/Source/CPack/cmCPackDocumentVariables.cxx +++ b/Source/CPack/cmCPackDocumentVariables.cxx @@ -44,14 +44,14 @@ void cmCPackDocumentVariables::DefineVariables(cmake* cm) "Boolean toggle to make CPack use DESTDIR mechanism when" " packaging.", "DESTDIR means DESTination DIRectory." " It is commonly used by makefile " - "users in order to install software at non-default location. It a" - "basic relocation mechanism. " + "users in order to install software at non-default location. It " + "is a basic relocation mechanism. " "It is usually invoked like this:\n" " make DESTDIR=/home/john install\n" "which will install the concerned software using the" " installation prefix, e.g. \"/usr/local\" prepended with " "the DESTDIR value which finally gives \"/home/john/usr/local\"." - " When preparing a package CPack first installs the items to be " + " When preparing a package, CPack first installs the items to be " "packaged in a local (to the build tree) directory by using the " "same DESTDIR mechanism. Nevertheless, if " "CPACK_SET_DESTDIR is set then CPack will set DESTDIR before" @@ -63,7 +63,7 @@ void cmCPackDocumentVariables::DefineVariables(cmake* cm) "Manually setting CPACK_SET_DESTDIR may help (or simply be" " necessary) if some install rules uses absolute " "DESTINATION (see CMake INSTALL command)." - "However, starting with" + " However, starting with" " CPack/CMake 2.8.3 RPM and DEB installers tries to handle DESTDIR" " automatically so that it is seldom necessary for the user to set" " it.", false, diff --git a/Source/CPack/cmCPackOSXX11Generator.cxx b/Source/CPack/cmCPackOSXX11Generator.cxx index 75ad640..363ccea 100644 --- a/Source/CPack/cmCPackOSXX11Generator.cxx +++ b/Source/CPack/cmCPackOSXX11Generator.cxx @@ -170,23 +170,25 @@ int cmCPackOSXX11Generator::PackageFiles() << "\" create -ov -format UDZO -srcfolder \"" << diskImageDirectory.c_str() << "\" \"" << packageFileNames[0] << "\""; - int retVal = 1; cmCPackLogger(cmCPackLog::LOG_VERBOSE, "Compress disk image using command: " << dmgCmd.str().c_str() << std::endl); // since we get random dashboard failures with this one // try running it more than once - int numTries = 4; + int retVal = 1; + int numTries = 10; bool res = false; while(numTries > 0) { res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &retVal, 0, this->GeneratorVerbose, 0); - if(res && retVal) + if ( res && !retVal ) { numTries = -1; + break; } + cmSystemTools::Delay(500); numTries--; } if ( !res || retVal ) diff --git a/Source/CPack/cmCPackPackageMakerGenerator.cxx b/Source/CPack/cmCPackPackageMakerGenerator.cxx index 7d00452..3a0e89b 100644 --- a/Source/CPack/cmCPackPackageMakerGenerator.cxx +++ b/Source/CPack/cmCPackPackageMakerGenerator.cxx @@ -319,17 +319,19 @@ int cmCPackPackageMakerGenerator::PackageFiles() << "\" \"" << packageFileNames[0] << "\""; std::string output; int retVal = 1; - int numTries = 4; + int numTries = 10; bool res = false; while(numTries > 0) { res = cmSystemTools::RunSingleCommand(dmgCmd.str().c_str(), &output, &retVal, 0, this->GeneratorVerbose, 0); - if(res && retVal) + if ( res && !retVal ) { numTries = -1; + break; } + cmSystemTools::Delay(500); numTries--; } if ( !res || retVal ) diff --git a/Source/CTest/cmCTestBuildHandler.cxx b/Source/CTest/cmCTestBuildHandler.cxx index 34a3e60..27bb06c 100644 --- a/Source/CTest/cmCTestBuildHandler.cxx +++ b/Source/CTest/cmCTestBuildHandler.cxx @@ -94,6 +94,7 @@ static const char* cmCTestErrorMatches[] = { ": Invalid argument", "^The project cannot be built\\.", "^\\[ERROR\\]", + "^Command .* failed with exit code", 0 }; diff --git a/Source/CTest/cmCTestMemCheckHandler.cxx b/Source/CTest/cmCTestMemCheckHandler.cxx index f0a98f9..035aaa9 100644 --- a/Source/CTest/cmCTestMemCheckHandler.cxx +++ b/Source/CTest/cmCTestMemCheckHandler.cxx @@ -679,7 +679,7 @@ bool cmCTestMemCheckHandler::ProcessMemCheckValgrindOutput( " bytes in [0-9,]+ blocks are definitely lost" " in loss record [0-9,]+ of [0-9,]+"); cmsys::RegularExpression vgPAR( - "== .*Syscall param .* contains unaddressable byte\\(s\\)"); + "== .*Syscall param .* (contains|points to) unaddressable byte\\(s\\)"); cmsys::RegularExpression vgMPK1( "== .*[0-9,]+ bytes in [0-9,]+ blocks are possibly lost in" " loss record [0-9,]+ of [0-9,]+"); diff --git a/Source/cmCommandArgumentParserHelper.h b/Source/cmCommandArgumentParserHelper.h index a211e95..cdb832b 100644 --- a/Source/cmCommandArgumentParserHelper.h +++ b/Source/cmCommandArgumentParserHelper.h @@ -81,7 +81,6 @@ private: cmStdString InputBuffer; std::vector<char> OutputBuffer; int CurrentLine; - int UnionsAvailable; int Verbose; void Print(const char* place, const char* str); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 57fd5b4..df78bf8 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -1772,6 +1772,7 @@ void cmComputeLinkInformation::GetRPath(std::vector<std::string>& runtimeDirs, !linking_for_install); bool use_link_rpath = outputRuntime && linking_for_install && + !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH") && this->Target->GetPropertyAsBool("INSTALL_RPATH_USE_LINK_PATH"); // Construct the RPATH. diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index 19558fa..9296d4c 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -260,12 +260,27 @@ bool cmDepends::CheckDependencies(std::istream& internalDepends, //---------------------------------------------------------------------------- void cmDepends::SetIncludePathFromLanguage(const char* lang) { + // Look for the new per "TARGET_" variant first: + const char * includePath = 0; std::string includePathVar = "CMAKE_"; includePathVar += lang; - includePathVar += "_INCLUDE_PATH"; + includePathVar += "_TARGET_INCLUDE_PATH"; cmMakefile* mf = this->LocalGenerator->GetMakefile(); - if(const char* includePath = mf->GetDefinition(includePathVar.c_str())) + includePath = mf->GetDefinition(includePathVar.c_str()); + if(includePath) { cmSystemTools::ExpandListArgument(includePath, this->IncludePath); } + else + { + // Fallback to the old directory level variable if no per-target var: + includePathVar = "CMAKE_"; + includePathVar += lang; + includePathVar += "_INCLUDE_PATH"; + includePath = mf->GetDefinition(includePathVar.c_str()); + if(includePath) + { + cmSystemTools::ExpandListArgument(includePath, this->IncludePath); + } + } } diff --git a/Source/cmDocumentVariables.cxx b/Source/cmDocumentVariables.cxx index a31dd01..897e516 100644 --- a/Source/cmDocumentVariables.cxx +++ b/Source/cmDocumentVariables.cxx @@ -355,7 +355,9 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "If this is set to TRUE, then the rpath information " "is not added to compiled executables. The default " "is to add rpath information if the platform supports it. " - "This allows for easy running from the build tree.",false, + "This allows for easy running from the build tree. To omit RPATH" + "in the install step, but not the build step, use " + "CMAKE_SKIP_INSTALL_RPATH instead.",false, "Variables that Provide Information"); cm->DefineProperty ("CMAKE_SOURCE_DIR", cmProperty::VARIABLE, @@ -1201,6 +1203,20 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "Variables that Control the Build"); cm->DefineProperty + ("CMAKE_SKIP_INSTALL_RPATH", cmProperty::VARIABLE, + "Do not include RPATHs in the install tree.", + "Normally CMake uses the build tree for the RPATH when building " + "executables etc on systems that use RPATH. When the software " + "is installed the executables etc are relinked by CMake to have " + "the install RPATH. If this variable is set to true then the software " + "is always installed without RPATH, even if RPATH is enabled when " + "building. This can be useful for example to allow running tests from " + "the build directory with RPATH enabled before the installation step. " + "To omit RPATH in both the build and install steps, use " + "CMAKE_SKIP_RPATH instead.",false, + "Variables that Control the Build"); + + cm->DefineProperty ("CMAKE_EXE_LINKER_FLAGS", cmProperty::VARIABLE, "Linker flags used to create executables.", "Flags used by the linker when creating an executable.",false, @@ -1278,6 +1294,22 @@ void cmDocumentVariables::DefineVariables(cmake* cm) "See that target property for additional information.", false, "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_WIN32_EXECUTABLE", cmProperty::VARIABLE, + "Default value for WIN32_EXECUTABLE of targets.", + "This variable is used to initialize the " + "WIN32_EXECUTABLE property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); + cm->DefineProperty + ("CMAKE_MACOSX_BUNDLE", cmProperty::VARIABLE, + "Default value for MACOSX_BUNDLE of targets.", + "This variable is used to initialize the " + "MACOSX_BUNDLE property on all the targets. " + "See that target property for additional information.", + false, + "Variables that Control the Build"); // Variables defined when the a language is enabled These variables will // also be defined whenever CMake has loaded its support for compiling (LANG) diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index ee37352..7728d74 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -30,12 +30,6 @@ cmExprParserHelper::~cmExprParserHelper() this->CleanupParser(); } -void cmExprParserHelper::SetLineFile(long line, const char* file) -{ - this->FileLine = line; - this->FileName = file; -} - int cmExprParserHelper::ParseString(const char* str, int verb) { if ( !str) diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h index 0c36b44..690426d 100644 --- a/Source/cmExprParserHelper.h +++ b/Source/cmExprParserHelper.h @@ -46,8 +46,6 @@ public: int GetResult() { return this->Result; } - void SetLineFile(long line, const char* file); - const char* GetError() { return this->ErrorString.c_str(); } private: @@ -55,7 +53,6 @@ private: cmStdString InputBuffer; std::vector<char> OutputBuffer; int CurrentLine; - int UnionsAvailable; int Verbose; void Print(const char* place, const char* str); diff --git a/Source/cmExtraCodeBlocksGenerator.cxx b/Source/cmExtraCodeBlocksGenerator.cxx index 6e246e6..ccb17f0 100644 --- a/Source/cmExtraCodeBlocksGenerator.cxx +++ b/Source/cmExtraCodeBlocksGenerator.cxx @@ -596,16 +596,17 @@ void cmExtraCodeBlocksGenerator::AppendTarget(cmGeneratedFileStream& fout, // the include directories for this target std::set<std::string> uniqIncludeDirs; - const std::vector<std::string>& incDirs = - target->GetMakefile()->GetIncludeDirectories(); - for(std::vector<std::string>::const_iterator dirIt=incDirs.begin(); - dirIt != incDirs.end(); + + std::vector<std::string> includes; + target->GetMakefile()->GetLocalGenerator()-> + GetIncludeDirectories(includes, target); + for(std::vector<std::string>::const_iterator dirIt=includes.begin(); + dirIt != includes.end(); ++dirIt) { uniqIncludeDirs.insert(*dirIt); } - std::string systemIncludeDirs = makefile->GetSafeDefinition( "CMAKE_EXTRA_GENERATOR_C_SYSTEM_INCLUDE_DIRS"); if (!systemIncludeDirs.empty()) diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index c8c86c7..ebd7c7f 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -893,9 +893,13 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const it != this->GlobalGenerator->GetLocalGenerators().end(); ++it) { - const std::vector<std::string>& includeDirs - = (*it)->GetMakefile()->GetIncludeDirectories(); - this->AppendIncludeDirectories(fout, includeDirs, emmited); + cmTargets & targets = (*it)->GetMakefile()->GetTargets(); + for (cmTargets::iterator l = targets.begin(); l != targets.end(); ++l) + { + std::vector<std::string> includeDirs; + (*it)->GetIncludeDirectories(includeDirs, &l->second); + this->AppendIncludeDirectories(fout, includeDirs, emmited); + } } // now also the system include directories, in case we found them in // CMakeSystemSpecificInformation.cmake. This makes Eclipse find the diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 9177162..f17002e 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -198,7 +198,7 @@ void cmFindPackageCommand::GenerateDocumentation() "If no such version file is available then the configuration file " "is assumed to not be compatible with any requested version. " "A basic version file containing generic version matching code can be " - "created using the macro write_basic_config_version_file(), see its " + "created using the macro write_basic_package_version_file(), see its " "documentation for more details. " "When a version file is found it is loaded to check the requested " "version number. " @@ -1062,6 +1062,10 @@ bool cmFindPackageCommand::HandlePackageMode() this->Makefile->IssueMessage( this->Required? cmake::FATAL_ERROR : cmake::WARNING, e.str()); + if (this->Required) + { + cmSystemTools::SetFatalErrorOccured(); + } if (!aw.str().empty()) { diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index 8dce053..a988844 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -1067,9 +1067,9 @@ void cmGlobalGenerator::CheckLocalGenerators() { manager = this->LocalGenerators[i]->GetMakefile()->GetCacheManager(); this->LocalGenerators[i]->ConfigureFinalPass(); - const cmTargets & targets = + cmTargets & targets = this->LocalGenerators[i]->GetMakefile()->GetTargets(); - for (cmTargets::const_iterator l = targets.begin(); + for (cmTargets::iterator l = targets.begin(); l != targets.end(); l++) { const cmTarget::LinkLibraryVectorType& libs = @@ -1095,27 +1095,28 @@ void cmGlobalGenerator::CheckLocalGenerators() notFoundMap[varName] = text; } } - } - const std::vector<std::string>& incs = - this->LocalGenerators[i]->GetMakefile()->GetIncludeDirectories(); + std::vector<std::string> incs; + this->LocalGenerators[i]->GetIncludeDirectories(incs, &l->second); - for( std::vector<std::string>::const_iterator incDir = incs.begin(); - incDir != incs.end(); ++incDir) - { - if(incDir->size() > 9 && - cmSystemTools::IsNOTFOUND(incDir->c_str())) + for( std::vector<std::string>::const_iterator incDir = incs.begin(); + incDir != incs.end(); ++incDir) { - std::string varName = incDir->substr(0, incDir->size()-9); - cmCacheManager::CacheIterator it = - manager->GetCacheIterator(varName.c_str()); - if(it.GetPropertyAsBool("ADVANCED")) + if(incDir->size() > 9 && + cmSystemTools::IsNOTFOUND(incDir->c_str())) { - varName += " (ADVANCED)"; + std::string varName = incDir->substr(0, incDir->size()-9); + cmCacheManager::CacheIterator it = + manager->GetCacheIterator(varName.c_str()); + if(it.GetPropertyAsBool("ADVANCED")) + { + varName += " (ADVANCED)"; + } + std::string text = notFoundMap[varName]; + text += "\n used as include directory in directory "; + text += this->LocalGenerators[i] + ->GetMakefile()->GetCurrentDirectory(); + notFoundMap[varName] = text; } - std::string text = notFoundMap[varName]; - text += "\n used as include directory in directory "; - text += this->LocalGenerators[i]->GetMakefile()->GetCurrentDirectory(); - notFoundMap[varName] = text; } } this->CMakeInstance->UpdateProgress diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx new file mode 100644 index 0000000..7c1529b --- /dev/null +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -0,0 +1,792 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmGlobalNinjaGenerator.h" +#include "cmLocalNinjaGenerator.h" +#include "cmMakefile.h" +#include "cmGeneratedFileStream.h" +#include "cmVersion.h" + +const char* cmGlobalNinjaGenerator::NINJA_BUILD_FILE = "build.ninja"; +const char* cmGlobalNinjaGenerator::NINJA_RULES_FILE = "rules.ninja"; +const char* cmGlobalNinjaGenerator::INDENT = " "; + +void cmGlobalNinjaGenerator::Indent(std::ostream& os, int count) +{ + for(int i = 0; i < count; ++i) + os << cmGlobalNinjaGenerator::INDENT; +} + +void cmGlobalNinjaGenerator::WriteDivider(std::ostream& os) +{ + os + << "# ======================================" + << "=======================================\n"; +} + +void cmGlobalNinjaGenerator::WriteComment(std::ostream& os, + const std::string& comment) +{ + if (comment.empty()) + return; + + std::string replace = comment; + std::string::size_type lpos = 0; + std::string::size_type rpos; + while((rpos = replace.find('\n', lpos)) != std::string::npos) + { + os << "# " << replace.substr(lpos, rpos - lpos) << "\n"; + lpos = rpos + 1; + } + os << "# " << replace.substr(lpos) << "\n"; +} + +static bool IsIdentChar(char c) +{ + return + ('a' <= c && c <= 'z') || + ('+' <= c && c <= '9') || // +,-./ and numbers + ('A' <= c && c <= 'Z') || + (c == '_') || (c == '$') || (c == '\\') || + (c == ' ') || (c == ':'); +} + +std::string cmGlobalNinjaGenerator::EncodeIdent(const std::string &ident, + std::ostream &vars) { + if (std::find_if(ident.begin(), ident.end(), + std::not1(std::ptr_fun(IsIdentChar))) != ident.end()) { + static unsigned VarNum = 0; + std::ostringstream names; + names << "ident" << VarNum++; + vars << names.str() << " = " << ident << "\n"; + return "$" + names.str(); + } else { + std::string result = ident; + cmSystemTools::ReplaceString(result, " ", "$ "); + cmSystemTools::ReplaceString(result, ":", "$:"); + return result; + } +} + +std::string cmGlobalNinjaGenerator::EncodeLiteral(const std::string &lit) +{ + std::string result = lit; + cmSystemTools::ReplaceString(result, "$", "$$"); + return result; +} + +std::string cmGlobalNinjaGenerator::EncodePath(const std::string &path) +{ + std::string result = path; +#ifdef _WIN32 + cmSystemTools::ReplaceString(result, "/", "\\"); +#endif + return EncodeLiteral(result); +} + +void cmGlobalNinjaGenerator::WriteBuild(std::ostream& os, + const std::string& comment, + const std::string& rule, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables) +{ + // Make sure there is a rule. + if(rule.empty()) + { + cmSystemTools::Error("No rule for WriteBuildStatement! called " + "with comment: ", + comment.c_str()); + return; + } + + // Make sure there is at least one output file. + if(outputs.empty()) + { + cmSystemTools::Error("No output files for WriteBuildStatement! called " + "with comment: ", + comment.c_str()); + return; + } + + cmGlobalNinjaGenerator::WriteComment(os, comment); + + std::ostringstream builds; + + // TODO: Better formatting for when there are multiple input/output files. + + // Write outputs files. + builds << "build"; + for(cmNinjaDeps::const_iterator i = outputs.begin(); + i != outputs.end(); + ++i) + builds << " " << EncodeIdent(EncodePath(*i), os); + builds << ":"; + + // Write the rule. + builds << " " << rule; + + // Write explicit dependencies. + for(cmNinjaDeps::const_iterator i = explicitDeps.begin(); + i != explicitDeps.end(); + ++i) + builds << " " << EncodeIdent(EncodePath(*i), os); + + // Write implicit dependencies. + if(!implicitDeps.empty()) + { + builds << " |"; + for(cmNinjaDeps::const_iterator i = implicitDeps.begin(); + i != implicitDeps.end(); + ++i) + builds << " " << EncodeIdent(EncodePath(*i), os); + } + + // Write order-only dependencies. + if(!orderOnlyDeps.empty()) + { + builds << " ||"; + for(cmNinjaDeps::const_iterator i = orderOnlyDeps.begin(); + i != orderOnlyDeps.end(); + ++i) + builds << " " << EncodeIdent(EncodePath(*i), os); + } + + builds << "\n"; + + os << builds.str(); + + // Write the variables bound to this build statement. + for(cmNinjaVars::const_iterator i = variables.begin(); + i != variables.end(); + ++i) + cmGlobalNinjaGenerator::WriteVariable(os, i->first, i->second, "", 1); +} + +void cmGlobalNinjaGenerator::WritePhonyBuild(std::ostream& os, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables) +{ + cmGlobalNinjaGenerator::WriteBuild(os, + comment, + "phony", + outputs, + explicitDeps, + implicitDeps, + orderOnlyDeps, + variables); +} + +void cmGlobalNinjaGenerator::AddCustomCommandRule() +{ + this->AddRule("CUSTOM_COMMAND", + "$COMMAND", + "$DESC", + "Rule for running custom commands.", + /*depfile*/ "", + /*restat*/ true); +} + +void +cmGlobalNinjaGenerator::WriteCustomCommandBuild(const std::string& command, + const std::string& description, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& deps, + const cmNinjaDeps& orderOnlyDeps) +{ + this->AddCustomCommandRule(); + + cmNinjaVars vars; + vars["COMMAND"] = command; + vars["DESC"] = EncodeLiteral(description); + + cmGlobalNinjaGenerator::WriteBuild(*this->BuildFileStream, + comment, + "CUSTOM_COMMAND", + outputs, + deps, + cmNinjaDeps(), + orderOnlyDeps, + vars); +} + +void cmGlobalNinjaGenerator::WriteRule(std::ostream& os, + const std::string& name, + const std::string& command, + const std::string& description, + const std::string& comment, + const std::string& depfile, + bool restat, + bool generator) +{ + // Make sure the rule has a name. + if(name.empty()) + { + cmSystemTools::Error("No name given for WriteRuleStatement! called " + "with comment: ", + comment.c_str()); + return; + } + + // Make sure a command is given. + if(command.empty()) + { + cmSystemTools::Error("No command given for WriteRuleStatement! called " + "with comment: ", + comment.c_str()); + return; + } + + cmGlobalNinjaGenerator::WriteComment(os, comment); + + // Write the rule. + os << "rule " << name << "\n"; + + // Write the depfile if any. + if(!depfile.empty()) + { + cmGlobalNinjaGenerator::Indent(os, 1); + os << "depfile = " << depfile << "\n"; + } + + // Write the command. + cmGlobalNinjaGenerator::Indent(os, 1); + os << "command = " << command << "\n"; + + // Write the description if any. + if(!description.empty()) + { + cmGlobalNinjaGenerator::Indent(os, 1); + os << "description = " << description << "\n"; + } + + if(restat) + { + cmGlobalNinjaGenerator::Indent(os, 1); + os << "restat = 1\n"; + } + + if(generator) + { + cmGlobalNinjaGenerator::Indent(os, 1); + os << "generator = 1\n"; + } +} + +void cmGlobalNinjaGenerator::WriteVariable(std::ostream& os, + const std::string& name, + const std::string& value, + const std::string& comment, + int indent) +{ + // Make sure we have a name. + if(name.empty()) + { + cmSystemTools::Error("No name given for WriteVariable! called " + "with comment: ", + comment.c_str()); + return; + } + + // Do not add a variable if the value is empty. + std::string val = cmSystemTools::TrimWhitespace(value); + if(val.empty()) + { + return; + } + + cmGlobalNinjaGenerator::WriteComment(os, comment); + cmGlobalNinjaGenerator::Indent(os, indent); + os << name << " = " << val << "\n"; +} + +void cmGlobalNinjaGenerator::WriteInclude(std::ostream& os, + const std::string& filename, + const std::string& comment) +{ + cmGlobalNinjaGenerator::WriteComment(os, comment); + os << "include " << filename << "\n"; +} + +void cmGlobalNinjaGenerator::WriteDefault(std::ostream& os, + const cmNinjaDeps& targets, + const std::string& comment) +{ + cmGlobalNinjaGenerator::WriteComment(os, comment); + os << "default"; + for(cmNinjaDeps::const_iterator i = targets.begin(); i != targets.end(); ++i) + os << " " << *i; + os << "\n"; +} + + +cmGlobalNinjaGenerator::cmGlobalNinjaGenerator() + : cmGlobalGenerator() + , BuildFileStream(0) + , RulesFileStream(0) + , Rules() + , AllDependencies() +{ + // // Ninja is not ported to non-Unix OS yet. + // this->ForceUnixPaths = true; + this->FindMakeProgramFile = "CMakeNinjaFindMake.cmake"; +} + +//---------------------------------------------------------------------------- +// Virtual public methods. + +cmLocalGenerator* cmGlobalNinjaGenerator::CreateLocalGenerator() +{ + cmLocalGenerator* lg = new cmLocalNinjaGenerator; + lg->SetGlobalGenerator(this); + return lg; +} + +void cmGlobalNinjaGenerator +::GetDocumentation(cmDocumentationEntry& entry) const +{ + entry.Name = this->GetName(); + entry.Brief = "Generates build.ninja files (experimental)."; + entry.Full = + "A build.ninja file is generated into the build tree. Recent " + "versions of the ninja program can build the project through the " + "\"all\" target. An \"install\" target is also provided."; +} + +// Implemented in all cmGlobaleGenerator sub-classes. +// Used in: +// Source/cmLocalGenerator.cxx +// Source/cmake.cxx +void cmGlobalNinjaGenerator::Generate() +{ + this->OpenBuildFileStream(); + this->OpenRulesFileStream(); + + this->cmGlobalGenerator::Generate(); + + this->WriteAssumedSourceDependencies(); + this->WriteTargetAliases(*this->BuildFileStream); + this->WriteBuiltinTargets(*this->BuildFileStream); + + this->CloseRulesFileStream(); + this->CloseBuildFileStream(); +} + +// Implemented in all cmGlobaleGenerator sub-classes. +// Used in: +// Source/cmMakefile.cxx: +void cmGlobalNinjaGenerator +::EnableLanguage(std::vector<std::string>const& languages, + cmMakefile *mf, + bool optional) +{ + this->cmGlobalGenerator::EnableLanguage(languages, mf, optional); + std::string path; + for(std::vector<std::string>::const_iterator l = languages.begin(); + l != languages.end(); ++l) + { + if(*l == "NONE") + { + continue; + } + if(*l == "Fortran") + { + std::string message = "The \""; + message += this->GetName(); + message += "\" generator does not support the language \""; + message += *l; + message += "\" yet."; + cmSystemTools::Error(message.c_str()); + } + this->ResolveLanguageCompiler(*l, mf, optional); + } +} + +// Implemented by: +// cmGlobalUnixMakefileGenerator3 +// cmGlobalVisualStudio10Generator +// cmGlobalVisualStudio6Generator +// cmGlobalVisualStudio7Generator +// cmGlobalXCodeGenerator +// Called by: +// cmGlobalGenerator::Build() +std::string cmGlobalNinjaGenerator +::GenerateBuildCommand(const char* makeProgram, + const char* projectName, + const char* additionalOptions, + const char* targetName, + const char* config, + bool ignoreErrors, + bool fast) +{ + // Project name and config are not used yet. + (void)projectName; + (void)config; + // Ninja does not have -i equivalent option yet. + (void)ignoreErrors; + // We do not handle fast build yet. + (void)fast; + + std::string makeCommand = + cmSystemTools::ConvertToUnixOutputPath(makeProgram); + + if(additionalOptions) + { + makeCommand += " "; + makeCommand += additionalOptions; + } + if(targetName) + { + if(strcmp(targetName, "clean") == 0) + { + makeCommand += " -t clean"; + } + else + { + makeCommand += " "; + makeCommand += targetName; + } + } + + return makeCommand; +} + +//---------------------------------------------------------------------------- +// Non-virtual public methods. + +void cmGlobalNinjaGenerator::AddRule(const std::string& name, + const std::string& command, + const std::string& description, + const std::string& comment, + const std::string& depfile, + bool restat, + bool generator) +{ + // Do not add the same rule twice. + if (this->HasRule(name)) + return; + + this->Rules.insert(name); + cmGlobalNinjaGenerator::WriteRule(*this->RulesFileStream, + name, + command, + description, + comment, + depfile, + restat, + generator); +} + +bool cmGlobalNinjaGenerator::HasRule(const std::string &name) +{ + RulesSetType::const_iterator rule = this->Rules.find(name); + return (rule != this->Rules.end()); +} + +//---------------------------------------------------------------------------- +// Private methods + +void cmGlobalNinjaGenerator::OpenBuildFileStream() +{ + // Compute Ninja's build file path. + std::string buildFilePath = + this->GetCMakeInstance()->GetHomeOutputDirectory(); + buildFilePath += "/"; + buildFilePath += cmGlobalNinjaGenerator::NINJA_BUILD_FILE; + + // Get a stream where to generate things. + if (!this->BuildFileStream) + { + this->BuildFileStream = new cmGeneratedFileStream(buildFilePath.c_str()); + if (!this->BuildFileStream) + { + // An error message is generated by the constructor if it cannot + // open the file. + return; + } + } + + // Write the do not edit header. + this->WriteDisclaimer(*this->BuildFileStream); + + // Write a comment about this file. + *this->BuildFileStream + << "# This file contains all the build statements describing the\n" + << "# compilation DAG.\n\n" + ; +} + +void cmGlobalNinjaGenerator::CloseBuildFileStream() +{ + if (this->BuildFileStream) + { + delete this->BuildFileStream; + this->BuildFileStream = 0; + } + else + { + cmSystemTools::Error("Build file stream was not open."); + } +} + +void cmGlobalNinjaGenerator::OpenRulesFileStream() +{ + // Compute Ninja's build file path. + std::string rulesFilePath = + this->GetCMakeInstance()->GetHomeOutputDirectory(); + rulesFilePath += "/"; + rulesFilePath += cmGlobalNinjaGenerator::NINJA_RULES_FILE; + + // Get a stream where to generate things. + if (!this->RulesFileStream) + { + this->RulesFileStream = new cmGeneratedFileStream(rulesFilePath.c_str()); + if (!this->RulesFileStream) + { + // An error message is generated by the constructor if it cannot + // open the file. + return; + } + } + + // Write the do not edit header. + this->WriteDisclaimer(*this->RulesFileStream); + + // Write comment about this file. + *this->RulesFileStream + << "# This file contains all the rules used to get the outputs files\n" + << "# built from the input files.\n" + << "# It is included in the main '" << NINJA_BUILD_FILE << "'.\n\n" + ; +} + +void cmGlobalNinjaGenerator::CloseRulesFileStream() +{ + if (this->RulesFileStream) + { + delete this->RulesFileStream; + this->RulesFileStream = 0; + } + else + { + cmSystemTools::Error("Rules file stream was not open."); + } +} + +void cmGlobalNinjaGenerator::WriteDisclaimer(std::ostream& os) +{ + os + << "# CMAKE generated file: DO NOT EDIT!\n" + << "# Generated by \"" << this->GetName() << "\"" + << " Generator, CMake Version " + << cmVersion::GetMajorVersion() << "." + << cmVersion::GetMinorVersion() << "\n\n"; +} + +void cmGlobalNinjaGenerator::AddDependencyToAll(cmTarget* target) +{ + this->AppendTargetOutputs(target, this->AllDependencies); +} + +void cmGlobalNinjaGenerator::WriteAssumedSourceDependencies() +{ + for (std::map<std::string, std::set<std::string> >::iterator + i = this->AssumedSourceDependencies.begin(); + i != this->AssumedSourceDependencies.end(); ++i) { + cmNinjaDeps deps; + std::copy(i->second.begin(), i->second.end(), std::back_inserter(deps)); + WriteCustomCommandBuild(/*command=*/"", /*description=*/"", + "Assume dependencies for generated source file.", + cmNinjaDeps(1, i->first), deps); + } +} + +void +cmGlobalNinjaGenerator +::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs) +{ + const char* configName = + target->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE"); + cmLocalNinjaGenerator *ng = + static_cast<cmLocalNinjaGenerator *>(this->LocalGenerators[0]); + + switch (target->GetType()) { + case cmTarget::EXECUTABLE: + case cmTarget::SHARED_LIBRARY: + case cmTarget::STATIC_LIBRARY: + case cmTarget::MODULE_LIBRARY: + outputs.push_back(ng->ConvertToNinjaPath( + target->GetFullPath(configName).c_str())); + break; + + case cmTarget::UTILITY: { + std::string path = ng->ConvertToNinjaPath( + target->GetMakefile()->GetStartOutputDirectory()); + if (path.empty() || path == ".") + outputs.push_back(target->GetName()); + else { + path += "/"; + path += target->GetName(); + outputs.push_back(path); + } + break; + } + + case cmTarget::GLOBAL_TARGET: + // Always use the target in HOME instead of an unused duplicate in a + // subdirectory. + outputs.push_back(target->GetName()); + break; + + default: + return; + } +} + +void +cmGlobalNinjaGenerator +::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs) +{ + if (target->GetType() == cmTarget::GLOBAL_TARGET) { + // Global targets only depend on other utilities, which may not appear in + // the TargetDepends set (e.g. "all"). + std::set<cmStdString> const& utils = target->GetUtilities(); + std::copy(utils.begin(), utils.end(), std::back_inserter(outputs)); + } else { + cmTargetDependSet const& targetDeps = + this->GetTargetDirectDepends(*target); + for (cmTargetDependSet::const_iterator i = targetDeps.begin(); + i != targetDeps.end(); ++i) { + this->AppendTargetOutputs(*i, outputs); + } + } +} + +void cmGlobalNinjaGenerator::AddTargetAlias(const std::string& alias, + cmTarget* target) { + cmNinjaDeps outputs; + this->AppendTargetOutputs(target, outputs); + // Mark the target's outputs as ambiguous to ensure that no other target uses + // the output as an alias. + for (cmNinjaDeps::iterator i = outputs.begin(); i != outputs.end(); ++i) + TargetAliases[*i] = 0; + + // Insert the alias into the map. If the alias was already present in the + // map and referred to another target, mark it as ambiguous. + std::pair<TargetAliasMap::iterator, bool> newAlias = + TargetAliases.insert(make_pair(alias, target)); + if (newAlias.second && newAlias.first->second != target) + newAlias.first->second = 0; +} + +void cmGlobalNinjaGenerator::WriteTargetAliases(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Target aliases.\n\n"; + + for (TargetAliasMap::iterator i = TargetAliases.begin(); + i != TargetAliases.end(); ++i) { + // Don't write ambiguous aliases. + if (!i->second) + continue; + + cmNinjaDeps deps; + this->AppendTargetOutputs(i->second, deps); + + cmGlobalNinjaGenerator::WritePhonyBuild(os, + "", + cmNinjaDeps(1, i->first), + deps); + } +} + +void cmGlobalNinjaGenerator::WriteBuiltinTargets(std::ostream& os) +{ + // Write headers. + cmGlobalNinjaGenerator::WriteDivider(os); + os << "# Built-in targets\n\n"; + + this->WriteTargetAll(os); + this->WriteTargetRebuildManifest(os); +} + +void cmGlobalNinjaGenerator::WriteTargetAll(std::ostream& os) +{ + cmNinjaDeps outputs; + outputs.push_back("all"); + + cmGlobalNinjaGenerator::WritePhonyBuild(os, + "The main all target.", + outputs, + this->AllDependencies); + + cmGlobalNinjaGenerator::WriteDefault(os, + outputs, + "Make the all target the default."); +} + +void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) +{ + cmLocalGenerator *lg = this->LocalGenerators[0]; + cmMakefile* mfRoot = lg->GetMakefile(); + + std::ostringstream cmd; + cmd << lg->ConvertToOutputFormat( + mfRoot->GetRequiredDefinition("CMAKE_COMMAND"), + cmLocalGenerator::SHELL) + << " -H" + << lg->ConvertToOutputFormat(mfRoot->GetHomeDirectory(), + cmLocalGenerator::SHELL) + << " -B" + << lg->ConvertToOutputFormat(mfRoot->GetHomeOutputDirectory(), + cmLocalGenerator::SHELL); + WriteRule(*this->RulesFileStream, + "RERUN_CMAKE", + cmd.str(), + "Re-running CMake...", + "Rule for re-running cmake.", + /*depfile=*/ "", + /*restat=*/ false, + /*generator=*/ true); + + cmNinjaDeps implicitDeps; + for (std::vector<cmLocalGenerator *>::const_iterator i = + this->LocalGenerators.begin(); i != this->LocalGenerators.end(); ++i) { + const std::vector<std::string>& lf = (*i)->GetMakefile()->GetListFiles(); + implicitDeps.insert(implicitDeps.end(), lf.begin(), lf.end()); + } + std::sort(implicitDeps.begin(), implicitDeps.end()); + implicitDeps.erase(std::unique(implicitDeps.begin(), implicitDeps.end()), + implicitDeps.end()); + implicitDeps.push_back("CMakeCache.txt"); + + WriteBuild(os, + "Re-run CMake if any of its inputs changed.", + "RERUN_CMAKE", + /*outputs=*/ cmNinjaDeps(1, NINJA_BUILD_FILE), + /*explicitDeps=*/ cmNinjaDeps(), + implicitDeps, + /*orderOnlyDeps=*/ cmNinjaDeps(), + /*variables=*/ cmNinjaVars()); + + WritePhonyBuild(os, + "A missing CMake input file is not an error.", + implicitDeps, + cmNinjaDeps()); +} diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h new file mode 100644 index 0000000..39df826 --- /dev/null +++ b/Source/cmGlobalNinjaGenerator.h @@ -0,0 +1,332 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmGlobalNinjaGenerator_h +# define cmGlobalNinjaGenerator_h + +# include "cmGlobalGenerator.h" +# include "cmNinjaTypes.h" + +class cmLocalGenerator; +class cmGeneratedFileStream; + +/** + * \class cmGlobalNinjaGenerator + * \brief Write a build.ninja file. + * + * The main differences between this generator and the UnixMakefile + * generator family are: + * - We don't care about VERBOSE variable or RULE_MESSAGES property since + * it is handle by Ninja's -v option. + * - We don't care about computing any progress status since Ninja manages + * it itself. + * - We don't care about generating a clean target since Ninja already have + * a clean tool. + * - We generate one build.ninja and one rules.ninja per project. + * - We try to minimize the number of generated rules: one per target and + * language. + * - We use Ninja special variable $in and $out to produce nice output. + * - We extensively use Ninja variable overloading system to minimize the + * number of generated rules. + */ +class cmGlobalNinjaGenerator : public cmGlobalGenerator +{ +public: + /// The default name of Ninja's build file. Typically: build.ninja. + static const char* NINJA_BUILD_FILE; + + /// The default name of Ninja's rules file. Typically: rules.ninja. + /// It is included in the main build.ninja file. + static const char* NINJA_RULES_FILE; + + /// The indentation string used when generating Ninja's build file. + static const char* INDENT; + + /// Write @a count times INDENT level to output stream @a os. + static void Indent(std::ostream& os, int count); + + /// Write a divider in the given output stream @a os. + static void WriteDivider(std::ostream& os); + + static std::string EncodeIdent(const std::string &ident, std::ostream &vars); + static std::string EncodeLiteral(const std::string &lit); + static std::string EncodePath(const std::string &path); + + /** + * Write the given @a comment to the output stream @a os. It + * handles new line character properly. + */ + static void WriteComment(std::ostream& os, const std::string& comment); + + /** + * Write a build statement to @a os with the @a comment using + * the @a rule the list of @a outputs files and inputs. + * It also writes the variables bound to this build statement. + * @warning no escaping of any kind is done here. + */ + static void WriteBuild(std::ostream& os, + const std::string& comment, + const std::string& rule, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, + const cmNinjaVars& variables); + + /** + * Helper to write a build statement with the special 'phony' rule. + */ + static void WritePhonyBuild(std::ostream& os, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& explicitDeps, + const cmNinjaDeps& implicitDeps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps(), + const cmNinjaVars& variables = cmNinjaVars()); + + void WriteCustomCommandBuild(const std::string& command, + const std::string& description, + const std::string& comment, + const cmNinjaDeps& outputs, + const cmNinjaDeps& deps = cmNinjaDeps(), + const cmNinjaDeps& orderOnlyDeps = cmNinjaDeps()); + + /** + * Write a rule statement named @a name to @a os with the @a comment, + * the mandatory @a command, the @a depfile and the @a description. + * It also writes the variables bound to this rule statement. + * @warning no escaping of any kind is done here. + */ + static void WriteRule(std::ostream& os, + const std::string& name, + const std::string& command, + const std::string& description, + const std::string& comment = "", + const std::string& depfile = "", + bool restat = false, + bool generator = false); + + /** + * Write a variable named @a name to @a os with value @a value and an + * optional @a comment. An @a indent level can be specified. + * @warning no escaping of any kind is done here. + */ + static void WriteVariable(std::ostream& os, + const std::string& name, + const std::string& value, + const std::string& comment = "", + int indent = 0); + + /** + * Write an include statement including @a filename with an optional + * @a comment to the @a os stream. + */ + static void WriteInclude(std::ostream& os, + const std::string& filename, + const std::string& comment = ""); + + /** + * Write a default target statement specifying @a targets as + * the default targets. + */ + static void WriteDefault(std::ostream& os, + const cmNinjaDeps& targets, + const std::string& comment = ""); + +public: + /// Default constructor. + cmGlobalNinjaGenerator(); + + /// Convenience method for creating an instance of this class. + static cmGlobalGenerator* New() { + return new cmGlobalNinjaGenerator; } + + /// Destructor. + virtual ~cmGlobalNinjaGenerator() { } + + /// Overloaded methods. @see cmGlobalGenerator::CreateLocalGenerator() + virtual cmLocalGenerator* CreateLocalGenerator(); + + /// Overloaded methods. @see cmGlobalGenerator::GetName(). + virtual const char* GetName() const { + return cmGlobalNinjaGenerator::GetActualName(); } + + /// @return the name of this generator. + static const char* GetActualName() { return "Ninja"; } + + /// Overloaded methods. @see cmGlobalGenerator::GetDocumentation() + virtual void GetDocumentation(cmDocumentationEntry& entry) const; + + /// Overloaded methods. @see cmGlobalGenerator::Generate() + virtual void Generate(); + + /// Overloaded methods. @see cmGlobalGenerator::EnableLanguage() + virtual void EnableLanguage(std::vector<std::string>const& languages, + cmMakefile* mf, + bool optional); + + /// Overloaded methods. @see cmGlobalGenerator::GenerateBuildCommand() + virtual std::string GenerateBuildCommand(const char* makeProgram, + const char* projectName, + const char* additionalOptions, + const char* targetName, + const char* config, + bool ignoreErrors, + bool fast); + + // Setup target names + virtual const char* GetAllTargetName() const { return "all"; } + virtual const char* GetInstallTargetName() const { return "install"; } + virtual const char* GetInstallLocalTargetName() const { + return "install/local"; + } + virtual const char* GetInstallStripTargetName() const { + return "install/strip"; + } + virtual const char* GetTestTargetName() const { return "test"; } + virtual const char* GetPackageTargetName() const { return "package"; } + virtual const char* GetPackageSourceTargetName() const { + return "package_source"; + } + virtual const char* GetEditCacheTargetName() const { + return "edit_cache"; + } + virtual const char* GetRebuildCacheTargetName() const { + return "rebuild_cache"; + } + virtual const char* GetCleanTargetName() const { return "clean"; } + +public: + cmGeneratedFileStream* GetBuildFileStream() const + { return this->BuildFileStream; } + + cmGeneratedFileStream* GetRulesFileStream() const + { return this->RulesFileStream; } + + /** + * Add a rule to the generated build system. + * Call WriteRule() behind the scene but perform some check before like: + * - Do not add twice the same rule. + */ + void AddRule(const std::string& name, + const std::string& command, + const std::string& description, + const std::string& comment = "", + const std::string& depfile = "", + bool restat = false, + bool generator = false); + + bool HasRule(const std::string& name); + + void AddCustomCommandRule(); + +protected: + + /// Overloaded methods. + /// @see cmGlobalGenerator::CheckALLOW_DUPLICATE_CUSTOM_TARGETS() + virtual bool CheckALLOW_DUPLICATE_CUSTOM_TARGETS() { return true; } + +private: + // In order to access the AddDependencyToAll() functions and co. + friend class cmLocalNinjaGenerator; + + // In order to access the SeenCustomCommand() function. + friend class cmNinjaTargetGenerator; + friend class cmNinjaNormalTargetGenerator; + friend class cmNinjaUtilityTargetGenerator; + +private: + void OpenBuildFileStream(); + void CloseBuildFileStream(); + + void OpenRulesFileStream(); + void CloseRulesFileStream(); + + /// Write the common disclaimer text at the top of each build file. + void WriteDisclaimer(std::ostream& os); + + void AddDependencyToAll(cmTarget* target); + + void WriteAssumedSourceDependencies(); + + void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs); + void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs); + + void AddTargetAlias(const std::string& alias, cmTarget* target); + void WriteTargetAliases(std::ostream& os); + + void WriteBuiltinTargets(std::ostream& os); + void WriteTargetAll(std::ostream& os); + void WriteTargetRebuildManifest(std::ostream& os); + + /// Called when we have seen the given custom command. Returns true + /// if we has seen it before. + bool SeenCustomCommand(cmCustomCommand const *cc) { + return !this->CustomCommands.insert(cc).second; + } + + /// Called when we have seen the given custom command output. + void SeenCustomCommandOutput(const std::string &output) { + this->CustomCommandOutputs.insert(output); + // We don't need the assumed dependencies anymore, because we have + // an output. + this->AssumedSourceDependencies.erase(output); + } + + bool HasCustomCommandOutput(const std::string &output) { + return this->CustomCommandOutputs.find(output) != + this->CustomCommandOutputs.end(); + } + + void AddAssumedSourceDependencies(const std::string &source, + const cmNinjaDeps &deps) { + std::set<std::string> &ASD = this->AssumedSourceDependencies[source]; + // Because we may see the same source file multiple times (same source + // specified in multiple targets), compute the union of any assumed + // dependencies. + ASD.insert(deps.begin(), deps.end()); + } + +private: + /// The file containing the build statement. (the relation ship of the + /// compilation DAG). + cmGeneratedFileStream* BuildFileStream; + /// The file containing the rule statements. (The action attached to each + /// edge of the compilation DAG). + cmGeneratedFileStream* RulesFileStream; + + /// The type used to store the set of rules added to the generated build + /// system. + typedef std::set<std::string> RulesSetType; + + /// The set of rules added to the generated build system. + RulesSetType Rules; + + /// The set of dependencies to add to the "all" target. + cmNinjaDeps AllDependencies; + + /// The set of custom commands we have seen. + std::set<cmCustomCommand const*> CustomCommands; + + /// The set of custom command outputs we have seen. + std::set<std::string> CustomCommandOutputs; + + /// The mapping from source file to assumed dependencies. + std::map<std::string, std::set<std::string> > AssumedSourceDependencies; + + typedef std::map<std::string, cmTarget*> TargetAliasMap; + TargetAliasMap TargetAliases; + + static cmLocalGenerator* LocalGenerator; +}; + +#endif // ! cmGlobalNinjaGenerator_h diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index b764660..0bbe0a0 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -188,8 +188,6 @@ void cmGlobalXCodeGenerator::EnableLanguage(std::vector<std::string>const& mf->AddDefinition("CMAKE_GENERATOR_CC", "gcc"); mf->AddDefinition("CMAKE_GENERATOR_CXX", "g++"); mf->AddDefinition("CMAKE_GENERATOR_NO_COMPILER_ENV", "1"); - // initialize Architectures so it can be used by - // GetTargetObjectFileDirectories this->cmGlobalGenerator::EnableLanguage(lang, mf, optional); const char* osxArch = mf->GetDefinition("CMAKE_OSX_ARCHITECTURES"); @@ -1820,7 +1818,7 @@ void cmGlobalXCodeGenerator::CreateBuildSettings(cmTarget& target, BuildObjectListOrString dirs(this, this->XcodeVersion >= 30); BuildObjectListOrString fdirs(this, this->XcodeVersion >= 30); std::vector<std::string> includes; - this->CurrentLocalGenerator->GetIncludeDirectories(includes); + this->CurrentLocalGenerator->GetIncludeDirectories(includes, &target); std::set<cmStdString> emitted; emitted.insert("/System/Library/Frameworks"); for(std::vector<std::string>::iterator i = includes.begin(); @@ -3372,37 +3370,6 @@ std::string cmGlobalXCodeGenerator::XCodeEscapePath(const char* p) } //---------------------------------------------------------------------------- -void cmGlobalXCodeGenerator:: -GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs) -{ - std::string dir = this->CurrentMakefile->GetCurrentOutputDirectory(); - dir += "/"; - dir += this->CurrentMakefile->GetProjectName(); - dir += ".build/"; - dir += this->GetCMakeCFGInitDirectory(); - dir += "/"; - dir += target->GetName(); - dir += ".build/Objects-normal/"; - std::string dirsave = dir; - if(this->Architectures.size()) - { - for(std::vector<std::string>::iterator i = this->Architectures.begin(); - i != this->Architectures.end(); ++i) - { - dir += *i; - dirs.push_back(dir); - dir = dirsave; - } - } - else - { - dirs.push_back(dir); - } -} - -//---------------------------------------------------------------------------- void cmGlobalXCodeGenerator ::AppendDirectoryForConfig(const char* prefix, diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index ed54be3..45f62eb 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -76,9 +76,6 @@ public: ///! What is the configurations directory variable called? virtual const char* GetCMakeCFGInitDirectory(); - void GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs); void SetCurrentLocalGenerator(cmLocalGenerator*); /** Return true if the generated build tree may contain multiple builds. diff --git a/Source/cmIncludeDirectoryCommand.h b/Source/cmIncludeDirectoryCommand.h index b90fe42..dcc116a 100644 --- a/Source/cmIncludeDirectoryCommand.h +++ b/Source/cmIncludeDirectoryCommand.h @@ -58,13 +58,21 @@ public: { return " include_directories([AFTER|BEFORE] [SYSTEM] dir1 dir2 ...)\n" - "Add the given directories to those searched by the compiler for " - "include files. By default the directories are appended onto " - "the current list of directories. This default behavior can be " - "changed by setting CMAKE_INCLUDE_DIRECTORIES_BEFORE to ON. " - "By using BEFORE or AFTER you can select between appending and " - "prepending, independent from the default. " - "If the SYSTEM option is given the compiler will be told that the " + "Add the given directories to those the compiler uses to search " + "for include files. " + "These directories are added to the directory property " + "INCLUDE_DIRECTORIES for the current CMakeLists file. " + "They are also added to the target property INCLUDE_DIRECTORIES " + "for each target in the current CMakeLists file. " + "The target property values are the ones used by the generators." + "\n" + "By default the directories are appended onto the current list of " + "directories. " + "This default behavior can be changed by setting " + "CMAKE_INCLUDE_DIRECTORIES_BEFORE to ON. " + "By using AFTER or BEFORE explicitly, you can select between " + "appending and prepending, independent of the default. " + "If the SYSTEM option is given, the compiler will be told the " "directories are meant as system include directories on some " "platforms."; } diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index dc8d1c4..a7f201c 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -556,7 +556,7 @@ void cmLocalGenerator::GenerateTargetManifest() void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname, const char* lang, cmSourceFile& source, - cmTarget& ) + cmTarget& target) { std::string objectDir = cmSystemTools::GetFilenamePath(std::string(ofname)); objectDir = this->Convert(objectDir.c_str(),START_OUTPUT,SHELL); @@ -574,7 +574,11 @@ void cmLocalGenerator::AddCustomCommandToCreateObject(const char* ofname, std::string flags; flags += this->Makefile->GetSafeDefinition(varString.c_str()); flags += " "; - flags += this->GetIncludeFlags(lang); + { + std::vector<std::string> includes; + this->GetIncludeDirectories(includes, &target, lang); + flags += this->GetIncludeFlags(includes, lang); + } flags += this->Makefile->GetDefineFlags(); // Construct the command lines. @@ -1192,24 +1196,16 @@ cmLocalGenerator::ConvertToIncludeReference(std::string const& path) } //---------------------------------------------------------------------------- -const char* cmLocalGenerator::GetIncludeFlags(const char* lang, - bool forResponseFile) +std::string cmLocalGenerator::GetIncludeFlags( + const std::vector<std::string> &includes, + const char* lang, bool forResponseFile) { if(!lang) { return ""; } - std::string key = lang; - key += forResponseFile? "@" : ""; - if(this->LanguageToIncludeFlags.count(key)) - { - return this->LanguageToIncludeFlags[key].c_str(); - } cmOStringStream includeFlags; - std::vector<std::string> includes; - this->GetIncludeDirectories(includes, lang); - std::vector<std::string>::iterator i; std::string flagVar = "CMAKE_INCLUDE_FLAG_"; flagVar += lang; @@ -1251,6 +1247,7 @@ const char* cmLocalGenerator::GetIncludeFlags(const char* lang, #ifdef __APPLE__ emitted.insert("/System/Library/Frameworks"); #endif + std::vector<std::string>::const_iterator i; for(i = includes.begin(); i != includes.end(); ++i) { if(this->Makefile->IsOn("APPLE") @@ -1311,16 +1308,12 @@ const char* cmLocalGenerator::GetIncludeFlags(const char* lang, { flags[flags.size()-1] = ' '; } - this->LanguageToIncludeFlags[key] = flags; - - // Use this temorary variable for the return value to work-around a - // bogus GCC 2.95 warning. - const char* ret = this->LanguageToIncludeFlags[key].c_str(); - return ret; + return flags; } //---------------------------------------------------------------------------- void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, + cmTarget* target, const char* lang) { // Need to decide whether to automatically include the source and @@ -1375,8 +1368,12 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, // Store the automatic include paths. if(includeBinaryDir) { - dirs.push_back(this->Makefile->GetStartOutputDirectory()); - emitted.insert(this->Makefile->GetStartOutputDirectory()); + if(emitted.find( + this->Makefile->GetStartOutputDirectory()) == emitted.end()) + { + dirs.push_back(this->Makefile->GetStartOutputDirectory()); + emitted.insert(this->Makefile->GetStartOutputDirectory()); + } } if(includeSourceDir) { @@ -1402,9 +1399,12 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } } - // Get the project-specified include directories. - std::vector<std::string>& includes = - this->Makefile->GetIncludeDirectories(); + // Get the target-specific include directories. + std::vector<std::string> includes; + if(target) + { + includes = target->GetIncludeDirectories(); + } // Support putting all the in-project include directories first if // it is requested by the project. @@ -1412,7 +1412,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, { const char* topSourceDir = this->Makefile->GetHomeDirectory(); const char* topBinaryDir = this->Makefile->GetHomeOutputDirectory(); - for(std::vector<std::string>::iterator i = includes.begin(); + for(std::vector<std::string>::const_iterator i = includes.begin(); i != includes.end(); ++i) { // Emit this directory only if it is a subdirectory of the @@ -1431,7 +1431,7 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } // Construct the final ordered include directory list. - for(std::vector<std::string>::iterator i = includes.begin(); + for(std::vector<std::string>::const_iterator i = includes.begin(); i != includes.end(); ++i) { if(emitted.insert(*i).second) @@ -1503,7 +1503,7 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); linkFlags += this->Convert(sf->GetFullPath().c_str(), - START_OUTPUT, SHELL); + FULL, SHELL); linkFlags += " "; } } @@ -1583,6 +1583,16 @@ void cmLocalGenerator::GetTargetFlags(std::string& linkLibs, this->Makefile->GetSafeDefinition("CMAKE_CREATE_CONSOLE_EXE"); linkFlags += " "; } + if (target.IsExecutableWithExports()) + { + std::string exportFlagVar = "CMAKE_EXE_EXPORTS_"; + exportFlagVar += linkLanguage; + exportFlagVar += "_FLAG"; + + linkFlags += + this->Makefile->GetSafeDefinition(exportFlagVar.c_str()); + linkFlags += " "; + } const char* targetLinkFlags = target.GetProperty("LINK_FLAGS"); if(targetLinkFlags) { @@ -2963,17 +2973,6 @@ cmLocalGenerator::GetTargetDirectory(cmTarget const&) const return ""; } - -//---------------------------------------------------------------------------- -void -cmLocalGenerator::GetTargetObjectFileDirectories(cmTarget* , - std::vector<std::string>& - ) -{ - cmSystemTools::Error("GetTargetObjectFileDirectories" - " called on cmLocalGenerator"); -} - //---------------------------------------------------------------------------- unsigned int cmLocalGenerator::GetBackwardsCompatibility() { diff --git a/Source/cmLocalGenerator.h b/Source/cmLocalGenerator.h index c3d057f..124747b 100644 --- a/Source/cmLocalGenerator.h +++ b/Source/cmLocalGenerator.h @@ -146,8 +146,8 @@ public: ///! Append flags to a string. virtual void AppendFlags(std::string& flags, const char* newFlags); ///! Get the include flags for the current makefile and language - const char* GetIncludeFlags(const char* lang, - bool forResponseFile = false); + std::string GetIncludeFlags(const std::vector<std::string> &includes, + const char* lang, bool forResponseFile = false); /** * Encode a list of preprocessor definitions for the compiler @@ -198,6 +198,7 @@ public: /** Get the include flags for the current makefile and language. */ void GetIncludeDirectories(std::vector<std::string>& dirs, + cmTarget* target, const char* lang = "C"); /** Compute the language used to compile the given source file. */ @@ -260,14 +261,6 @@ public: }; FortranFormat GetFortranFormat(const char* value); - /** Return the directories into which object files will be put. - * There maybe more than one for fat binary systems like OSX. - */ - virtual void - GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs); - /** * Convert the given remote path to a relative path with respect to * the given local path. The local path must be given in component @@ -395,7 +388,6 @@ protected: std::vector<std::string> StartOutputDirectoryComponents; cmLocalGenerator* Parent; std::vector<cmLocalGenerator*> Children; - std::map<cmStdString, cmStdString> LanguageToIncludeFlags; std::map<cmStdString, cmStdString> UniqueObjectNamesMap; std::string::size_type ObjectPathMax; std::set<cmStdString> ObjectMaxPathViolations; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx new file mode 100644 index 0000000..78072b5 --- /dev/null +++ b/Source/cmLocalNinjaGenerator.cxx @@ -0,0 +1,424 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmLocalNinjaGenerator.h" +#include "cmCustomCommandGenerator.h" +#include "cmMakefile.h" +#include "cmGlobalNinjaGenerator.h" +#include "cmNinjaTargetGenerator.h" +#include "cmGeneratedFileStream.h" +#include "cmSourceFile.h" +#include "cmComputeLinkInformation.h" +#include "cmake.h" + +#include <assert.h> + +cmLocalNinjaGenerator::cmLocalNinjaGenerator() + : cmLocalGenerator() + , ConfigName("") + , HomeRelativeOutputPath("") +{ + this->IsMakefileGenerator = true; +#ifdef _WIN32 + this->WindowsShell = true; +#endif + this->TargetImplib = "$TARGET_IMPLIB"; +} + +//---------------------------------------------------------------------------- +// Virtual public methods. + +cmLocalNinjaGenerator::~cmLocalNinjaGenerator() +{ +} + +void cmLocalNinjaGenerator::Generate() +{ + this->SetConfigName(); + + this->WriteProcessedMakefile(this->GetBuildFileStream()); + this->WriteProcessedMakefile(this->GetRulesFileStream()); + + this->WriteBuildFileTop(); + + cmTargets& targets = this->GetMakefile()->GetTargets(); + for(cmTargets::iterator t = targets.begin(); t != targets.end(); ++t) + { + cmNinjaTargetGenerator* tg = cmNinjaTargetGenerator::New(&t->second); + if(tg) + { + tg->Generate(); + // Add the target to "all" if required. + if (!this->GetGlobalNinjaGenerator()->IsExcluded( + this->GetGlobalNinjaGenerator()->LocalGenerators[0], + t->second)) + this->GetGlobalNinjaGenerator()->AddDependencyToAll(&t->second); + delete tg; + } + } + + this->WriteCustomCommandBuildStatements(); +} + +// Implemented in: +// cmLocalUnixMakefileGenerator3. +// Used in: +// Source/cmMakefile.cxx +// Source/cmGlobalGenerator.cxx +void cmLocalNinjaGenerator::Configure() +{ + // Compute the path to use when referencing the current output + // directory from the top output directory. + this->HomeRelativeOutputPath = + this->Convert(this->Makefile->GetStartOutputDirectory(), HOME_OUTPUT); + if(this->HomeRelativeOutputPath == ".") + { + this->HomeRelativeOutputPath = ""; + } + this->cmLocalGenerator::Configure(); + +} + +// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it. +std::string cmLocalNinjaGenerator +::GetTargetDirectory(cmTarget const& target) const +{ + std::string dir = cmake::GetCMakeFilesDirectoryPostSlash(); + dir += target.GetName(); +#if defined(__VMS) + dir += "_dir"; +#else + dir += ".dir"; +#endif + return dir; +} + +//---------------------------------------------------------------------------- +// Non-virtual public methods. + +const cmGlobalNinjaGenerator* +cmLocalNinjaGenerator::GetGlobalNinjaGenerator() const +{ + return + static_cast<const cmGlobalNinjaGenerator*>(this->GetGlobalGenerator()); +} + +cmGlobalNinjaGenerator* cmLocalNinjaGenerator::GetGlobalNinjaGenerator() +{ + return static_cast<cmGlobalNinjaGenerator*>(this->GetGlobalGenerator()); +} + +// TODO: Picked up from cmLocalUnixMakefileGenerator3. Refactor it. +std::string +cmLocalNinjaGenerator +::GetObjectFileName(const cmTarget& target, + const cmSourceFile& source) +{ + // Make sure we never hit this old case. + if(source.GetProperty("MACOSX_PACKAGE_LOCATION")) + { + std::string msg = "MACOSX_PACKAGE_LOCATION set on source file: "; + msg += source.GetFullPath(); + this->GetMakefile()->IssueMessage(cmake::INTERNAL_ERROR, + msg.c_str()); + } + + // Start with the target directory. + std::string obj = this->GetTargetDirectory(target); + obj += "/"; + + // Get the object file name without the target directory. + std::string dir_max; + dir_max += this->Makefile->GetCurrentOutputDirectory(); + dir_max += "/"; + dir_max += obj; + std::string objectName = + this->GetObjectFileNameWithoutTarget(source, dir_max, 0); + // Append the object name to the target directory. + obj += objectName; + return obj; +} + +//---------------------------------------------------------------------------- +// Virtual protected methods. + +std::string +cmLocalNinjaGenerator::ConvertToLinkReference(std::string const& lib) +{ + return this->Convert(lib.c_str(), HOME_OUTPUT, SHELL); +} + +std::string +cmLocalNinjaGenerator::ConvertToIncludeReference(std::string const& path) +{ + return this->Convert(path.c_str(), HOME_OUTPUT, SHELL); +} + +//---------------------------------------------------------------------------- +// Private methods. + +cmGeneratedFileStream& cmLocalNinjaGenerator::GetBuildFileStream() const +{ + return *this->GetGlobalNinjaGenerator()->GetBuildFileStream(); +} + +cmGeneratedFileStream& cmLocalNinjaGenerator::GetRulesFileStream() const +{ + return *this->GetGlobalNinjaGenerator()->GetRulesFileStream(); +} + +const cmake* cmLocalNinjaGenerator::GetCMakeInstance() const +{ + return this->GetGlobalGenerator()->GetCMakeInstance(); +} + +cmake* cmLocalNinjaGenerator::GetCMakeInstance() +{ + return this->GetGlobalGenerator()->GetCMakeInstance(); +} + +bool cmLocalNinjaGenerator::isRootMakefile() const +{ + return (strcmp(this->Makefile->GetCurrentDirectory(), + this->GetCMakeInstance()->GetHomeDirectory()) == 0); +} + +void cmLocalNinjaGenerator::WriteBuildFileTop() +{ + // We do that only once for the top CMakeLists.txt file. + if(!this->isRootMakefile()) + return; + + // For the build file. + this->WriteProjectHeader(this->GetBuildFileStream()); + this->WriteNinjaFilesInclusion(this->GetBuildFileStream()); + + // For the rule file. + this->WriteProjectHeader(this->GetRulesFileStream()); +} + +void cmLocalNinjaGenerator::WriteProjectHeader(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os + << "# Project: " << this->GetMakefile()->GetProjectName() << std::endl + << "# Configuration: " << this->ConfigName << std::endl + ; + cmGlobalNinjaGenerator::WriteDivider(os); +} + +void cmLocalNinjaGenerator::WriteNinjaFilesInclusion(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os + << "# Include auxiliary files.\n" + << "\n" + ; + cmGlobalNinjaGenerator::WriteInclude(os, + cmGlobalNinjaGenerator::NINJA_RULES_FILE, + "Include rules file."); + os << "\n"; +} + +void cmLocalNinjaGenerator::SetConfigName() +{ + // Store the configuration name that will be generated. + if(const char* config = + this->GetMakefile()->GetDefinition("CMAKE_BUILD_TYPE")) + { + // Use the build type given by the user. + this->ConfigName = config; + } + else + { + // No configuration type given. + this->ConfigName = ""; + } +} + +void cmLocalNinjaGenerator::WriteProcessedMakefile(std::ostream& os) +{ + cmGlobalNinjaGenerator::WriteDivider(os); + os + << "# Write statements declared in CMakeLists.txt:" << std::endl + << "# " << this->Makefile->GetCurrentListFile() << std::endl + ; + if(this->isRootMakefile()) + os << "# Which is the root file." << std::endl; + cmGlobalNinjaGenerator::WriteDivider(os); + os << std::endl; +} + +std::string cmLocalNinjaGenerator::ConvertToNinjaPath(const char *path) +{ + std::string convPath = this->Convert(path, cmLocalGenerator::HOME_OUTPUT); +#ifdef _WIN32 + cmSystemTools::ReplaceString(convPath, "/", "\\"); +#endif + return convPath; +} + +void +cmLocalNinjaGenerator +::AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs) +{ + this->GetGlobalNinjaGenerator()->AppendTargetOutputs(target, outputs); +} + +void +cmLocalNinjaGenerator +::AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs) +{ + this->GetGlobalNinjaGenerator()->AppendTargetDepends(target, outputs); +} + +void cmLocalNinjaGenerator::AppendCustomCommandDeps(const cmCustomCommand *cc, + cmNinjaDeps &ninjaDeps) +{ + const std::vector<std::string> &deps = cc->GetDepends(); + for (std::vector<std::string>::const_iterator i = deps.begin(); + i != deps.end(); ++i) { + std::string dep; + if (this->GetRealDependency(i->c_str(), this->GetConfigName(), dep)) + ninjaDeps.push_back(ConvertToNinjaPath(dep.c_str())); + } +} + +std::string cmLocalNinjaGenerator::BuildCommandLine( + const std::vector<std::string> &cmdLines) +{ + // If we have no commands but we need to build a command anyway, use ":". + // This happens when building a POST_BUILD value for link targets that + // don't use POST_BUILD. + if (cmdLines.empty()) +#ifdef _WIN32 + return "cd."; +#else + return ":"; +#endif + + // TODO: This will work only on Unix platforms. I don't + // want to use a link.txt file because I will lose the benefit of the + // $in variables. A discussion about dealing with multiple commands in + // a rule is started here: + // groups.google.com/group/ninja-build/browse_thread/thread/d515f23a78986008 + std::ostringstream cmd; + for (std::vector<std::string>::const_iterator li = cmdLines.begin(); + li != cmdLines.end(); ++li) { + if (li != cmdLines.begin()) + cmd << " && "; + cmd << *li; + } + return cmd.str(); +} + +void cmLocalNinjaGenerator::AppendCustomCommandLines(const cmCustomCommand *cc, + std::vector<std::string> &cmdLines) +{ + cmCustomCommandGenerator ccg(*cc, this->GetConfigName(), this->Makefile); + if (ccg.GetNumberOfCommands() > 0) { + const char* wd = cc->GetWorkingDirectory(); + if (!wd) + wd = this->GetMakefile()->GetStartOutputDirectory(); + + std::ostringstream cdCmd; + cdCmd << "cd " << this->ConvertToOutputFormat(wd, SHELL); + cmdLines.push_back(cdCmd.str()); + } + for (unsigned i = 0; i != ccg.GetNumberOfCommands(); ++i) { + cmdLines.push_back(this->ConvertToOutputFormat(ccg.GetCommand(i).c_str(), + SHELL)); + std::string& cmd = cmdLines.back(); + ccg.AppendArguments(i, cmd); + } +} + +void +cmLocalNinjaGenerator::WriteCustomCommandBuildStatement( + cmCustomCommand const *cc, const cmNinjaDeps& orderOnlyDeps) +{ + if (this->GetGlobalNinjaGenerator()->SeenCustomCommand(cc)) + return; + + const std::vector<std::string> &outputs = cc->GetOutputs(); + cmNinjaDeps ninjaOutputs(outputs.size()), ninjaDeps; + + std::transform(outputs.begin(), outputs.end(), + ninjaOutputs.begin(), MapToNinjaPath()); + this->AppendCustomCommandDeps(cc, ninjaDeps); + + for (cmNinjaDeps::iterator i = ninjaOutputs.begin(); i != ninjaOutputs.end(); + ++i) + this->GetGlobalNinjaGenerator()->SeenCustomCommandOutput(*i); + + std::vector<std::string> cmdLines; + this->AppendCustomCommandLines(cc, cmdLines); + + if (cmdLines.empty()) { + cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), + "Phony custom command for " + + ninjaOutputs[0], + ninjaOutputs, + ninjaDeps, + cmNinjaDeps(), + orderOnlyDeps, + cmNinjaVars()); + } else { + this->GetGlobalNinjaGenerator()->WriteCustomCommandBuild( + this->BuildCommandLine(cmdLines), + this->ConstructComment(*cc), + "Custom command for " + ninjaOutputs[0], + ninjaOutputs, + ninjaDeps, + orderOnlyDeps); + } +} + +void cmLocalNinjaGenerator::AddCustomCommandTarget(cmCustomCommand const* cc, + cmTarget* target) +{ + this->CustomCommandTargets[cc].insert(target); +} + +void cmLocalNinjaGenerator::WriteCustomCommandBuildStatements() +{ + for (CustomCommandTargetMap::iterator i = this->CustomCommandTargets.begin(); + i != this->CustomCommandTargets.end(); ++i) { + // A custom command may appear on multiple targets. However, some build + // systems exist where the target dependencies on some of the targets are + // overspecified, leading to a dependency cycle. If we assume all target + // dependencies are a superset of the true target dependencies for this + // custom command, we can take the set intersection of all target + // dependencies to obtain a correct dependency list. + // + // FIXME: This won't work in certain obscure scenarios involving indirect + // dependencies. + std::set<cmTarget*>::iterator j = i->second.begin(); + assert(j != i->second.end()); + std::vector<std::string> ccTargetDeps; + this->AppendTargetDepends(*j, ccTargetDeps); + std::sort(ccTargetDeps.begin(), ccTargetDeps.end()); + ++j; + + for (; j != i->second.end(); ++j) { + std::vector<std::string> jDeps, depsIntersection; + this->AppendTargetDepends(*j, jDeps); + std::sort(jDeps.begin(), jDeps.end()); + std::set_intersection(ccTargetDeps.begin(), ccTargetDeps.end(), + jDeps.begin(), jDeps.end(), + std::back_inserter(depsIntersection)); + ccTargetDeps = depsIntersection; + } + + this->WriteCustomCommandBuildStatement(i->first, ccTargetDeps); + } +} diff --git a/Source/cmLocalNinjaGenerator.h b/Source/cmLocalNinjaGenerator.h new file mode 100644 index 0000000..28b431d --- /dev/null +++ b/Source/cmLocalNinjaGenerator.h @@ -0,0 +1,136 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmLocalNinjaGenerator_h +# define cmLocalNinjaGenerator_h + +# include "cmLocalGenerator.h" +# include "cmNinjaTypes.h" + +class cmGlobalNinjaGenerator; +class cmGeneratedFileStream; +class cmake; + +/** + * \class cmLocalNinjaGenerator + * \brief Write a local build.ninja file. + * + * cmLocalNinjaGenerator produces a local build.ninja file from its + * member Makefile. + */ +class cmLocalNinjaGenerator : public cmLocalGenerator +{ +public: + /// Default constructor. + cmLocalNinjaGenerator(); + + /// Destructor. + virtual ~cmLocalNinjaGenerator(); + + /// Overloaded methods. @see cmLocalGenerator::Generate() + virtual void Generate(); + + /// Overloaded methods. @see cmLocalGenerator::Configure() + virtual void Configure(); + + /// Overloaded methods. @see cmLocalGenerator::GetTargetDirectory() + virtual std::string GetTargetDirectory(cmTarget const& target) const; + +public: + const cmGlobalNinjaGenerator* GetGlobalNinjaGenerator() const; + cmGlobalNinjaGenerator* GetGlobalNinjaGenerator(); + + /** + * Shortcut to get the cmake instance throw the global generator. + * @return an instance of the cmake object. + */ + const cmake* GetCMakeInstance() const; + cmake* GetCMakeInstance(); + + const char* GetConfigName() const + { return this->ConfigName.c_str(); } + + std::string GetObjectFileName(const cmTarget& target, + const cmSourceFile& source); + + /// @return whether we are processing the top CMakeLists.txt file. + bool isRootMakefile() const; + + /// @returns the relative path between the HomeOutputDirectory and this + /// local generators StartOutputDirectory. + std::string GetHomeRelativeOutputPath() const + { return this->HomeRelativeOutputPath; } + +protected: + virtual std::string ConvertToLinkReference(std::string const& lib); + virtual std::string ConvertToIncludeReference(std::string const& path); + +private: + friend class cmGlobalNinjaGenerator; + + // In order to access to protected member of the local generator. + friend class cmNinjaTargetGenerator; + friend class cmNinjaNormalTargetGenerator; + friend class cmNinjaUtilityTargetGenerator; + +private: + cmGeneratedFileStream& GetBuildFileStream() const; + cmGeneratedFileStream& GetRulesFileStream() const; + + void WriteBuildFileTop(); + void WriteProjectHeader(std::ostream& os); + void WriteNinjaFilesInclusion(std::ostream& os); + void WriteProcessedMakefile(std::ostream& os); + + void SetConfigName(); + + std::string ConvertToNinjaPath(const char *path); + + struct map_to_ninja_path; + friend struct map_to_ninja_path; + struct map_to_ninja_path { + cmLocalNinjaGenerator *LocalGenerator; + map_to_ninja_path(cmLocalNinjaGenerator *LocalGen) + : LocalGenerator(LocalGen) {} + std::string operator()(const std::string &path) { + return LocalGenerator->ConvertToNinjaPath(path.c_str()); + } + }; + map_to_ninja_path MapToNinjaPath() { + return map_to_ninja_path(this); + } + + void AppendTargetOutputs(cmTarget* target, cmNinjaDeps& outputs); + void AppendTargetDepends(cmTarget* target, cmNinjaDeps& outputs); + + void AppendCustomCommandDeps(const cmCustomCommand *cc, + cmNinjaDeps &ninjaDeps); + std::string BuildCommandLine(const std::vector<std::string> &cmdLines); + void AppendCustomCommandLines(const cmCustomCommand *cc, + std::vector<std::string> &cmdLines); + void WriteCustomCommandRule(); + void WriteCustomCommandBuildStatement(cmCustomCommand const *cc, + const cmNinjaDeps& orderOnlyDeps); + + void AddCustomCommandTarget(cmCustomCommand const* cc, cmTarget* target); + void WriteCustomCommandBuildStatements(); + +private: + std::string ConfigName; + std::string HomeRelativeOutputPath; + + typedef std::map<cmCustomCommand const*, std::set<cmTarget*> > + CustomCommandTargetMap; + CustomCommandTargetMap CustomCommandTargets; +}; + +#endif // ! cmLocalNinjaGenerator_h diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index dd313ca..fdf59b2 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -145,6 +145,20 @@ void cmLocalUnixMakefileGenerator3::Generate() } //---------------------------------------------------------------------------- +void cmLocalUnixMakefileGenerator3::AddLocalObjectFile( + cmTarget* target, cmSourceFile* sf, std::string objNoTargetDir, + bool hasSourceExtension) +{ + if(cmSystemTools::FileIsFullPath(objNoTargetDir.c_str())) + { + objNoTargetDir = cmSystemTools::GetFilenameName(objNoTargetDir); + } + LocalObjectInfo& info = this->LocalObjectFiles[objNoTargetDir]; + info.HasSourceExtension = hasSourceExtension; + info.push_back(LocalObjectEntry(target, sf->GetLanguage())); +} + +//---------------------------------------------------------------------------- void cmLocalUnixMakefileGenerator3::GetIndividualFileTargets (std::vector<std::string>& targets) { @@ -452,28 +466,6 @@ void cmLocalUnixMakefileGenerator3::WriteDirectoryInformationFile() << "\n"; } - // Store the include search path for this directory. - infoFileStream - << "# The C and CXX include file search paths:\n"; - infoFileStream - << "SET(CMAKE_C_INCLUDE_PATH\n"; - std::vector<std::string> includeDirs; - this->GetIncludeDirectories(includeDirs); - for(std::vector<std::string>::iterator i = includeDirs.begin(); - i != includeDirs.end(); ++i) - { - infoFileStream - << " \"" << this->Convert(i->c_str(),HOME_OUTPUT).c_str() << "\"\n"; - } - infoFileStream - << " )\n"; - infoFileStream - << "SET(CMAKE_CXX_INCLUDE_PATH ${CMAKE_C_INCLUDE_PATH})\n"; - infoFileStream - << "SET(CMAKE_Fortran_INCLUDE_PATH ${CMAKE_C_INCLUDE_PATH})\n"; - infoFileStream - << "SET(CMAKE_ASM_INCLUDE_PATH ${CMAKE_C_INCLUDE_PATH})\n"; - // Store the include regular expressions for this directory. infoFileStream << "\n" @@ -2289,14 +2281,3 @@ void cmLocalUnixMakefileGenerator3 } } } - - -void cmLocalUnixMakefileGenerator3 -::GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& dirs) -{ - std::string dir = this->Makefile->GetCurrentOutputDirectory(); - dir += "/"; - dir += this->GetTargetDirectory(*target); - dirs.push_back(dir); -} diff --git a/Source/cmLocalUnixMakefileGenerator3.h b/Source/cmLocalUnixMakefileGenerator3.h index 45ac21d..4bde082 100644 --- a/Source/cmLocalUnixMakefileGenerator3.h +++ b/Source/cmLocalUnixMakefileGenerator3.h @@ -225,24 +225,9 @@ public: // write the target rules for the local Makefile into the stream void WriteLocalAllRules(std::ostream& ruleFileStream); - struct LocalObjectEntry - { - cmTarget* Target; - std::string Language; - LocalObjectEntry(): Target(0), Language() {} - LocalObjectEntry(cmTarget* t, const char* lang): - Target(t), Language(lang) {} - }; - struct LocalObjectInfo: public std::vector<LocalObjectEntry> - { - bool HasSourceExtension; - bool HasPreprocessRule; - bool HasAssembleRule; - LocalObjectInfo():HasSourceExtension(false), HasPreprocessRule(false), - HasAssembleRule(false) {} - }; - std::map<cmStdString, LocalObjectInfo> const& GetLocalObjectFiles() - { return this->LocalObjectFiles;} + void AddLocalObjectFile(cmTarget* target, cmSourceFile* sf, + std::string objNoTargetDir, + bool hasSourceExtension); std::vector<cmStdString> const& GetLocalHelp() { return this->LocalHelp; } @@ -257,9 +242,6 @@ public: { return !this->SkipAssemblySourceRules; } - // Get the directories into which the .o files will go for this target - void GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& dirs); // Fill the vector with the target names for the object files, // preprocessed files and assembly files. Currently only used by the @@ -301,9 +283,6 @@ protected: void WriteTargetRequiresRule(std::ostream& ruleFileStream, cmTarget& target, const std::vector<std::string>& objects); - void WriteObjectConvenienceRule(std::ostream& ruleFileStream, - const char* comment, const char* output, - LocalObjectInfo const& info); std::string GetObjectFileName(cmTarget& target, const cmSourceFile& source, @@ -378,7 +357,27 @@ private: bool SkipPreprocessedSourceRules; bool SkipAssemblySourceRules; + struct LocalObjectEntry + { + cmTarget* Target; + std::string Language; + LocalObjectEntry(): Target(0), Language() {} + LocalObjectEntry(cmTarget* t, const char* lang): + Target(t), Language(lang) {} + }; + struct LocalObjectInfo: public std::vector<LocalObjectEntry> + { + bool HasSourceExtension; + bool HasPreprocessRule; + bool HasAssembleRule; + LocalObjectInfo():HasSourceExtension(false), HasPreprocessRule(false), + HasAssembleRule(false) {} + }; std::map<cmStdString, LocalObjectInfo> LocalObjectFiles; + void WriteObjectConvenienceRule(std::ostream& ruleFileStream, + const char* comment, const char* output, + LocalObjectInfo const& info); + std::vector<cmStdString> LocalHelp; /* does the work for each target */ diff --git a/Source/cmLocalVisualStudio6Generator.cxx b/Source/cmLocalVisualStudio6Generator.cxx index 1dfcbea..678c5bf 100644 --- a/Source/cmLocalVisualStudio6Generator.cxx +++ b/Source/cmLocalVisualStudio6Generator.cxx @@ -103,52 +103,9 @@ void cmLocalVisualStudio6Generator::OutputDSPFile() } } - // Setup /I and /LIBPATH options for the resulting DSP file. VS 6 - // truncates long include paths so make it as short as possible if - // the length threatens this problem. - unsigned int maxIncludeLength = 3000; - bool useShortPath = false; - for(int j=0; j < 2; ++j) - { - std::vector<std::string> includes; - this->GetIncludeDirectories(includes); - std::vector<std::string>::iterator i; - for(i = includes.begin(); i != includes.end(); ++i) - { - std::string tmp = - this->ConvertToOptionallyRelativeOutputPath(i->c_str()); - if(useShortPath) - { - cmSystemTools::GetShortPath(tmp.c_str(), tmp); - } - this->IncludeOptions += " /I "; - - // quote if not already quoted - if (tmp[0] != '"') - { - this->IncludeOptions += "\""; - this->IncludeOptions += tmp; - this->IncludeOptions += "\""; - } - else - { - this->IncludeOptions += tmp; - } - } - if(j == 0 && this->IncludeOptions.size() > maxIncludeLength) - { - this->IncludeOptions = ""; - useShortPath = true; - } - else - { - break; - } - } - // Create the DSP or set of DSP's for libraries and executables - cmTargets &tgts = this->Makefile->GetTargets(); + cmTargets &tgts = this->Makefile->GetTargets(); for(cmTargets::iterator l = tgts.begin(); l != tgts.end(); l++) { @@ -380,7 +337,7 @@ void cmLocalVisualStudio6Generator::WriteDSPFile(std::ostream& fout, } // Compute which sources need unique object computation. - this->ComputeObjectNameRequirements(sourceGroups); + this->ComputeObjectNameRequirements(classes); // Write the DSP file's header. this->WriteDSPHeader(fout, libName, target, sourceGroups); @@ -895,6 +852,61 @@ inline std::string removeQuotes(const std::string& s) return s; } + +std::string +cmLocalVisualStudio6Generator::GetTargetIncludeOptions(cmTarget &target) +{ + std::string includeOptions; + + // Setup /I and /LIBPATH options for the resulting DSP file. VS 6 + // truncates long include paths so make it as short as possible if + // the length threatens this problem. + unsigned int maxIncludeLength = 3000; + bool useShortPath = false; + for(int j=0; j < 2; ++j) + { + std::vector<std::string> includes; + this->GetIncludeDirectories(includes, &target); + + std::vector<std::string>::iterator i; + for(i = includes.begin(); i != includes.end(); ++i) + { + std::string tmp = + this->ConvertToOptionallyRelativeOutputPath(i->c_str()); + if(useShortPath) + { + cmSystemTools::GetShortPath(tmp.c_str(), tmp); + } + includeOptions += " /I "; + + // quote if not already quoted + if (tmp[0] != '"') + { + includeOptions += "\""; + includeOptions += tmp; + includeOptions += "\""; + } + else + { + includeOptions += tmp; + } + } + + if(j == 0 && includeOptions.size() > maxIncludeLength) + { + includeOptions = ""; + useShortPath = true; + } + else + { + break; + } + } + + return includeOptions; +} + + // Code in blocks surrounded by a test for this definition is needed // only for compatibility with user project's replacement DSP // templates. The CMake templates no longer use them. @@ -1132,6 +1144,9 @@ void cmLocalVisualStudio6Generator } #endif + // Get include options for this target. + std::string includeOptions = this->GetTargetIncludeOptions(target); + // Get extra linker options for this target type. std::string extraLinkOptions; std::string extraLinkOptionsDebug; @@ -1510,7 +1525,7 @@ void cmLocalVisualStudio6Generator optionsRelWithDebInfo.c_str()); cmSystemTools::ReplaceString(line, "BUILD_INCLUDES", - this->IncludeOptions.c_str()); + includeOptions.c_str()); cmSystemTools::ReplaceString(line, "TARGET_VERSION_FLAG", targetVersionFlag.c_str()); cmSystemTools::ReplaceString(line, "TARGET_IMPLIB_FLAG_DEBUG", @@ -1605,11 +1620,13 @@ void cmLocalVisualStudio6Generator flagsDebugRel = this->Makefile->GetSafeDefinition(flagVar.c_str()); flagsDebugRel += " -DCMAKE_INTDIR=\\\"RelWithDebInfo\\\" "; } - - // if unicode is not found, then add -D_MBCS + + // if _UNICODE and _SBCS are not found, then add -D_MBCS std::string defs = this->Makefile->GetDefineFlags(); if(flags.find("D_UNICODE") == flags.npos && - defs.find("D_UNICODE") == flags.npos) + defs.find("D_UNICODE") == flags.npos && + flags.find("D_SBCS") == flags.npos && + defs.find("D_SBCS") == flags.npos) { flags += " /D \"_MBCS\""; } @@ -1778,17 +1795,6 @@ cmLocalVisualStudio6Generator return ""; } -void cmLocalVisualStudio6Generator -::GetTargetObjectFileDirectories(cmTarget* , - std::vector<std::string>& - dirs) -{ - std::string dir = this->Makefile->GetCurrentOutputDirectory(); - dir += "/"; - dir += this->GetGlobalGenerator()->GetCMakeCFGInitDirectory(); - dirs.push_back(dir); -} - std::string cmLocalVisualStudio6Generator ::GetConfigName(std::string const& configuration) const diff --git a/Source/cmLocalVisualStudio6Generator.h b/Source/cmLocalVisualStudio6Generator.h index 195d654..4e588c3 100644 --- a/Source/cmLocalVisualStudio6Generator.h +++ b/Source/cmLocalVisualStudio6Generator.h @@ -50,9 +50,6 @@ public: void SetBuildType(BuildType, const char* libName, cmTarget&); virtual std::string GetTargetDirectory(cmTarget const& target) const; - void GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs); private: std::string DSPHeaderTemplate; std::string DSPFooterTemplate; @@ -89,7 +86,7 @@ private: void ComputeLinkOptions(cmTarget& target, const char* configName, const std::string extraOptions, std::string& options); - std::string IncludeOptions; + std::string GetTargetIncludeOptions(cmTarget &target); std::vector<std::string> Configurations; std::string GetConfigName(std::string const& configuration) const; diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 11a0387..c5714cc 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -774,6 +774,10 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, { fout << "\t\t\tCharacterSet=\"1\">\n"; } + else if(targetOptions.UsingSBCS()) + { + fout << "\t\t\tCharacterSet=\"0\">\n"; + } else { fout << "\t\t\tCharacterSet=\"2\">\n"; @@ -807,7 +811,7 @@ void cmLocalVisualStudio7Generator::WriteConfiguration(std::ostream& fout, targetOptions.OutputAdditionalOptions(fout, "\t\t\t\t", "\n"); fout << "\t\t\t\tAdditionalIncludeDirectories=\""; std::vector<std::string> includes; - this->GetIncludeDirectories(includes); + this->GetIncludeDirectories(includes, &target); std::vector<std::string>::iterator i = includes.begin(); for(;i != includes.end(); ++i) { @@ -1307,7 +1311,7 @@ void cmLocalVisualStudio7Generator::WriteVCProjFile(std::ostream& fout, } // Compute which sources need unique object computation. - this->ComputeObjectNameRequirements(sourceGroups); + this->ComputeObjectNameRequirements(classes); // open the project this->WriteProjectStart(fout, libName, target, sourceGroups); @@ -2114,19 +2118,6 @@ std::string cmLocalVisualStudio7Generator return dir; } -void cmLocalVisualStudio7Generator:: -GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs) -{ - std::string dir = this->Makefile->GetCurrentOutputDirectory(); - dir += "/"; - dir += this->GetTargetDirectory(*target); - dir += "/"; - dir += this->GetGlobalGenerator()->GetCMakeCFGInitDirectory(); - dirs.push_back(dir); -} - //---------------------------------------------------------------------------- #include <windows.h> static bool cmLVS6G_IsFAT(const char* dir) diff --git a/Source/cmLocalVisualStudio7Generator.h b/Source/cmLocalVisualStudio7Generator.h index 5b634b8..6ddf82a 100644 --- a/Source/cmLocalVisualStudio7Generator.h +++ b/Source/cmLocalVisualStudio7Generator.h @@ -54,9 +54,6 @@ public: void SetBuildType(BuildType,const char *name); void SetPlatformName(const char* n) { this->PlatformName = n;} - void GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs); void SetExtraFlagTable(cmVS7FlagTable const* table) { this->ExtraFlagTable = table; } diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index de1ac30..f389b35 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -83,77 +83,50 @@ bool cmLocalVisualStudioGenerator::SourceFileCompiles(const cmSourceFile* sf) } //---------------------------------------------------------------------------- -void cmLocalVisualStudioGenerator::CountObjectNames( - const std::vector<cmSourceGroup>& groups, - std::map<cmStdString, int>& counts) +void +cmLocalVisualStudioGenerator::ComputeObjectNameRequirements( + std::vector<cmSourceFile*> const& sources + ) { - for(unsigned int i = 0; i < groups.size(); ++i) + // Clear the current set of requirements. + this->NeedObjectName.clear(); + + // Count the number of object files with each name. Note that + // windows file names are not case sensitive. + std::map<cmStdString, int> counts; + for(std::vector<cmSourceFile*>::const_iterator s = sources.begin(); + s != sources.end(); ++s) { - cmSourceGroup sg = groups[i]; - std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles(); - for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin(); - s != srcs.end(); ++s) + const cmSourceFile* sf = *s; + if(this->SourceFileCompiles(sf)) { - const cmSourceFile* sf = *s; - if(this->SourceFileCompiles(sf)) - { - std::string objectName = cmSystemTools::LowerCase( - cmSystemTools::GetFilenameWithoutLastExtension( - sf->GetFullPath())); - objectName += ".obj"; - counts[objectName] += 1; - } + std::string objectName = cmSystemTools::LowerCase( + cmSystemTools::GetFilenameWithoutLastExtension( + sf->GetFullPath())); + objectName += ".obj"; + counts[objectName] += 1; } - this->CountObjectNames(sg.GetGroupChildren(), counts); } -} -//---------------------------------------------------------------------------- -void cmLocalVisualStudioGenerator::InsertNeedObjectNames( - const std::vector<cmSourceGroup>& groups, - std::map<cmStdString, int>& count) -{ - for(unsigned int i = 0; i < groups.size(); ++i) + // For all source files producing duplicate names we need unique + // object name computation. + for(std::vector<cmSourceFile*>::const_iterator s = sources.begin(); + s != sources.end(); ++s) { - cmSourceGroup sg = groups[i]; - std::vector<const cmSourceFile*> const& srcs = sg.GetSourceFiles(); - for(std::vector<const cmSourceFile*>::const_iterator s = srcs.begin(); - s != srcs.end(); ++s) + const cmSourceFile* sf = *s; + if(this->SourceFileCompiles(sf)) { - const cmSourceFile* sf = *s; - if(this->SourceFileCompiles(sf)) + std::string objectName = cmSystemTools::LowerCase( + cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())); + objectName += ".obj"; + if(counts[objectName] > 1) { - std::string objectName = cmSystemTools::LowerCase( - cmSystemTools::GetFilenameWithoutLastExtension(sf->GetFullPath())); - objectName += ".obj"; - if(count[objectName] > 1) - { - this->NeedObjectName.insert(sf); - } + this->NeedObjectName.insert(sf); } } - this->InsertNeedObjectNames(sg.GetGroupChildren(), count); } } - -//---------------------------------------------------------------------------- -void cmLocalVisualStudioGenerator::ComputeObjectNameRequirements -(std::vector<cmSourceGroup> const& sourceGroups) -{ - // Clear the current set of requirements. - this->NeedObjectName.clear(); - - // Count the number of object files with each name. Note that - // windows file names are not case sensitive. - std::map<cmStdString, int> objectNameCounts; - this->CountObjectNames(sourceGroups, objectNameCounts); - - // For all source files producing duplicate names we need unique - // object name computation. - this->InsertNeedObjectNames(sourceGroups, objectNameCounts); -} - //---------------------------------------------------------------------------- const char* cmLocalVisualStudioGenerator::ReportErrorLabel() const { diff --git a/Source/cmLocalVisualStudioGenerator.h b/Source/cmLocalVisualStudioGenerator.h index fcf1f21..e58c757 100644 --- a/Source/cmLocalVisualStudioGenerator.h +++ b/Source/cmLocalVisualStudioGenerator.h @@ -65,12 +65,8 @@ protected: MaybeCreateImplibDir(cmTarget& target, const char* config, bool isFortran); // Safe object file name generation. - void ComputeObjectNameRequirements(std::vector<cmSourceGroup> const&); + void ComputeObjectNameRequirements(std::vector<cmSourceFile*> const&); bool SourceFileCompiles(const cmSourceFile* sf); - void CountObjectNames(const std::vector<cmSourceGroup>& groups, - std::map<cmStdString, int>& count); - void InsertNeedObjectNames(const std::vector<cmSourceGroup>& groups, - std::map<cmStdString, int>& count); std::set<const cmSourceFile*> NeedObjectName; friend class cmVisualStudio10TargetGenerator; diff --git a/Source/cmLocalXCodeGenerator.cxx b/Source/cmLocalXCodeGenerator.cxx index b989870..551ebd3 100644 --- a/Source/cmLocalXCodeGenerator.cxx +++ b/Source/cmLocalXCodeGenerator.cxx @@ -33,16 +33,3 @@ cmLocalXCodeGenerator::GetTargetDirectory(cmTarget const&) const // No per-target directory for this generator (yet). return ""; } - -//---------------------------------------------------------------------------- -void cmLocalXCodeGenerator:: -GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs) -{ - cmGlobalXCodeGenerator* g = - (cmGlobalXCodeGenerator*)this->GetGlobalGenerator(); - g->SetCurrentLocalGenerator(this); - g->GetTargetObjectFileDirectories(target, - dirs); -} diff --git a/Source/cmLocalXCodeGenerator.h b/Source/cmLocalXCodeGenerator.h index 1ab805d..eab228f 100644 --- a/Source/cmLocalXCodeGenerator.h +++ b/Source/cmLocalXCodeGenerator.h @@ -27,9 +27,6 @@ public: cmLocalXCodeGenerator(); virtual ~cmLocalXCodeGenerator(); - void GetTargetObjectFileDirectories(cmTarget* target, - std::vector<std::string>& - dirs); virtual std::string GetTargetDirectory(cmTarget const& target) const; private: diff --git a/Source/cmMakeDepend.cxx b/Source/cmMakeDepend.cxx index 0b4eea5..6055c55 100644 --- a/Source/cmMakeDepend.cxx +++ b/Source/cmMakeDepend.cxx @@ -54,16 +54,33 @@ void cmMakeDepend::SetMakefile(cmMakefile* makefile) this->Makefile->IncludeFileRegularExpression.c_str()); this->ComplainFileRegularExpression.compile( this->Makefile->ComplainFileRegularExpression.c_str()); - - // Now extract any include paths from the makefile flags - const std::vector<std::string>& includes = - this->Makefile->GetIncludeDirectories(); - for(std::vector<std::string>::const_iterator j = includes.begin(); - j != includes.end(); ++j) + + // Now extract any include paths from the targets + std::set<std::string> uniqueIncludes; + std::vector<std::string> orderedAndUniqueIncludes; + cmTargets & targets = this->Makefile->GetTargets(); + for (cmTargets::iterator l = targets.begin(); l != targets.end(); ++l) + { + const std::vector<std::string>& includes = + l->second.GetIncludeDirectories(); + for(std::vector<std::string>::const_iterator j = includes.begin(); + j != includes.end(); ++j) + { + std::string path = *j; + this->Makefile->ExpandVariablesInString(path); + if(uniqueIncludes.insert(path).second) + { + orderedAndUniqueIncludes.push_back(path); + } + } + } + + for(std::vector<std::string>::const_iterator + it = orderedAndUniqueIncludes.begin(); + it != orderedAndUniqueIncludes.end(); + ++it) { - std::string path = *j; - this->Makefile->ExpandVariablesInString(path); - this->AddSearchPath(path.c_str()); + this->AddSearchPath(it->c_str()); } } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index fdf5b31..f90c35c 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -116,7 +116,6 @@ cmMakefile::cmMakefile(const cmMakefile& mf): Internal(new Internals) this->Targets = mf.Targets; this->SourceFiles = mf.SourceFiles; this->Tests = mf.Tests; - this->IncludeDirectories = mf.IncludeDirectories; this->LinkDirectories = mf.LinkDirectories; this->SystemIncludeDirectories = mf.SystemIncludeDirectories; this->ListFiles = mf.ListFiles; @@ -210,9 +209,9 @@ cmMakefile::~cmMakefile() { delete *i; } - for(unsigned int i=0; i < this->UsedCommands.size(); i++) + for(unsigned int i=0; i < this->FinalPassCommands.size(); i++) { - delete this->UsedCommands[i]; + delete this->FinalPassCommands[i]; } std::vector<cmFunctionBlocker*>::iterator pos; for (pos = this->FunctionBlockers.begin(); @@ -278,8 +277,6 @@ void cmMakefile::Print() this->cmHomeDirectory.c_str() << std::endl; std::cout << " this->ProjectName; " << this->ProjectName.c_str() << std::endl; - this->PrintStringVector("this->IncludeDirectories;", - this->IncludeDirectories); this->PrintStringVector("this->LinkDirectories", this->LinkDirectories); #if defined(CMAKE_BUILD_WITH_CMAKE) for( std::vector<cmSourceGroup>::const_iterator i = @@ -421,7 +418,7 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, else if(pcmd->HasFinalPass()) { // use the command - this->UsedCommands.push_back(pcmd.release()); + this->FinalPassCommands.push_back(pcmd.release()); } } else if ( this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE @@ -813,8 +810,8 @@ void cmMakefile::FinalPass() // give all the commands a chance to do something // after the file has been parsed before generation - for(std::vector<cmCommand*>::iterator i = this->UsedCommands.begin(); - i != this->UsedCommands.end(); ++i) + for(std::vector<cmCommand*>::iterator i = this->FinalPassCommands.begin(); + i != this->FinalPassCommands.end(); ++i) { (*i)->FinalPass(); } @@ -1478,7 +1475,8 @@ void cmMakefile::InitializeFromParent() this->Internal->VarStack.top() = parent->Internal->VarStack.top().Closure(); // copy include paths - this->IncludeDirectories = parent->IncludeDirectories; + this->SetProperty("INCLUDE_DIRECTORIES", + parent->GetProperty("INCLUDE_DIRECTORIES")); this->SystemIncludeDirectories = parent->SystemIncludeDirectories; // define flags @@ -1603,42 +1601,61 @@ void cmMakefile::AddSubDirectory(const char* srcPath, const char *binPath, } } -void cmMakefile::AddIncludeDirectory(const char* inc, bool before) +//---------------------------------------------------------------------------- +void AddStringToProperty(cmProperty *prop, const char* name, const char* s, + bool before) { - // if there is a newline then break it into multiple arguments - if (!inc) + if (!prop) { return; } - // Don't add an include directory that is already present. Yes, - // this linear search results in n^2 behavior, but n won't be - // getting much bigger than 20. We cannot use a set because of - // order dependency of the include path. - std::vector<std::string>::iterator i = - std::find(this->IncludeDirectories.begin(), - this->IncludeDirectories.end(), inc); - if(i == this->IncludeDirectories.end()) + // Don't worry about duplicates at this point. We eliminate them when + // we convert the property to a vector in GetIncludeDirectories. + + if (before) { - if (before) + const char *val = prop->GetValue(); + cmOStringStream oss; + + if(val && *val) { - // WARNING: this *is* expensive (linear time) since it's a vector - this->IncludeDirectories.insert(this->IncludeDirectories.begin(), inc); + oss << s << ";" << val; } else { - this->IncludeDirectories.push_back(inc); + oss << s; } + + std::string newVal = oss.str(); + prop->Set(name, newVal.c_str()); } else { - if(before) - { - // if this before and already in the path then remove it - this->IncludeDirectories.erase(i); - // WARNING: this *is* expensive (linear time) since it's a vector - this->IncludeDirectories.insert(this->IncludeDirectories.begin(), inc); - } + prop->Append(name, s); + } +} + +//---------------------------------------------------------------------------- +void cmMakefile::AddIncludeDirectory(const char* inc, bool before) +{ + if (!inc) + { + return; + } + + // Directory property: + cmProperty *prop = + this->GetProperties().GetOrCreateProperty("INCLUDE_DIRECTORIES"); + AddStringToProperty(prop, "INCLUDE_DIRECTORIES", inc, before); + + // Property on each target: + for (cmTargets::iterator l = this->Targets.begin(); + l != this->Targets.end(); ++l) + { + cmTarget &t = l->second; + prop = t.GetProperties().GetOrCreateProperty("INCLUDE_DIRECTORIES"); + AddStringToProperty(prop, "INCLUDE_DIRECTORIES", inc, before); } } @@ -2093,17 +2110,37 @@ void cmMakefile::AddExtraDirectory(const char* dir) } -// expance CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the +// expand CMAKE_BINARY_DIR and CMAKE_SOURCE_DIR in the // include and library directories. void cmMakefile::ExpandVariables() { // Now expand variables in the include and link strings - for(std::vector<std::string>::iterator d = this->IncludeDirectories.begin(); - d != this->IncludeDirectories.end(); ++d) + + // May not be necessary anymore... But may need a policy for strict + // backwards compatibility + const char *includeDirs = this->GetProperty("INCLUDE_DIRECTORIES"); + if (includeDirs) { - this->ExpandVariablesInString(*d, true, true); + std::string dirs = includeDirs; + this->ExpandVariablesInString(dirs, true, true); + this->SetProperty("INCLUDE_DIRECTORIES", dirs.c_str()); + } + + // Also for each target's INCLUDE_DIRECTORIES property: + for (cmTargets::iterator l = this->Targets.begin(); + l != this->Targets.end(); ++l) + { + cmTarget &t = l->second; + includeDirs = t.GetProperty("INCLUDE_DIRECTORIES"); + if (includeDirs) + { + std::string dirs = includeDirs; + this->ExpandVariablesInString(dirs, true, true); + t.SetProperty("INCLUDE_DIRECTORIES", dirs.c_str()); + } } + for(std::vector<std::string>::iterator d = this->LinkDirectories.begin(); d != this->LinkDirectories.end(); ++d) { @@ -3317,16 +3354,6 @@ void cmMakefile::SetProperty(const char* prop, const char* value) // handle special props std::string propname = prop; - if ( propname == "INCLUDE_DIRECTORIES" ) - { - std::vector<std::string> varArgsExpanded; - if(value) - { - cmSystemTools::ExpandListArgument(value, varArgsExpanded); - } - this->SetIncludeDirectories(varArgsExpanded); - return; - } if ( propname == "LINK_DIRECTORIES" ) { @@ -3368,17 +3395,6 @@ void cmMakefile::AppendProperty(const char* prop, const char* value, // handle special props std::string propname = prop; - if ( propname == "INCLUDE_DIRECTORIES" ) - { - std::vector<std::string> varArgsExpanded; - cmSystemTools::ExpandListArgument(value, varArgsExpanded); - for(std::vector<std::string>::const_iterator vi = varArgsExpanded.begin(); - vi != varArgsExpanded.end(); ++vi) - { - this->AddIncludeDirectory(vi->c_str()); - } - return; - } if ( propname == "LINK_DIRECTORIES" ) { @@ -3474,23 +3490,6 @@ const char *cmMakefile::GetProperty(const char* prop, output += this->DefineFlagsOrig; return output.c_str(); } - else if (!strcmp("INCLUDE_DIRECTORIES",prop) ) - { - cmOStringStream str; - for (std::vector<std::string>::const_iterator - it = this->GetIncludeDirectories().begin(); - it != this->GetIncludeDirectories().end(); - ++ it ) - { - if ( it != this->GetIncludeDirectories().begin()) - { - str << ";"; - } - str << it->c_str(); - } - output = str.str(); - return output.c_str(); - } else if (!strcmp("LINK_DIRECTORIES",prop)) { cmOStringStream str; @@ -3861,9 +3860,22 @@ void cmMakefile::DefineProperties(cmake *cm) cm->DefineProperty ("INCLUDE_DIRECTORIES", cmProperty::DIRECTORY, "List of preprocessor include file search directories.", - "This read-only property specifies the list of directories given " - "so far to the include_directories command. " - "It is intended for debugging purposes.", false); + "This property specifies the list of directories given " + "so far to the include_directories command. " + "This property exists on directories and targets. " + "In addition to accepting values from the include_directories " + "command, values may be set directly on any directory or any " + "target using the set_property command. " + "A target gets its initial value for this property from the value " + "of the directory property. " + "A directory gets its initial value from its parent directory if " + "it has one. " + "Both directory and target property values are adjusted by calls " + "to the include_directories command." + "\n" + "The target property values are used by the generators to set " + "the include paths for the compiler. " + "See also the include_directories command."); cm->DefineProperty ("LINK_DIRECTORIES", cmProperty::DIRECTORY, diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index 1c46a73..960ba39 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -522,22 +522,6 @@ public: cmTarget* FindTargetToUse(const char* name); /** - * Get a list of include directories in the build. - */ - std::vector<std::string>& GetIncludeDirectories() - { - return this->IncludeDirectories; - } - const std::vector<std::string>& GetIncludeDirectories() const - { - return this->IncludeDirectories; - } - void SetIncludeDirectories(const std::vector<std::string>& vec) - { - this->IncludeDirectories = vec; - } - - /** * Mark include directories as system directories. */ void AddSystemIncludeDirectory(const char* dir); @@ -620,12 +604,6 @@ public: */ bool CanIWriteThisFile(const char* fileName); - /** - * Get the vector of used command instances. - */ - const std::vector<cmCommand*>& GetUsedCommands() const - {return this->UsedCommands;} - #if defined(CMAKE_BUILD_WITH_CMAKE) /** * Get the vector source groups. @@ -880,9 +858,7 @@ protected: // Tests std::map<cmStdString, cmTest*> Tests; - // The include and link-library paths. These may have order - // dependency, so they must be vectors (not set). - std::vector<std::string> IncludeDirectories; + // The link-library paths. Order matters, use std::vector (not std::set). std::vector<std::string> LinkDirectories; // The set of include directories that are marked as system include @@ -913,7 +889,7 @@ protected: std::vector<cmSourceGroup> SourceGroups; #endif - std::vector<cmCommand*> UsedCommands; + std::vector<cmCommand*> FinalPassCommands; cmLocalGenerator* LocalGenerator; bool IsFunctionBlocked(const cmListFileFunction& lff, cmExecutionStatus &status); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index a3a832b..b9120c4 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -489,16 +489,8 @@ void cmMakefileTargetGenerator::WriteObjectRuleFiles(cmSourceFile& source) srcFullPath.c_str()); // add this to the list of objects for this local generator - if(cmSystemTools::FileIsFullPath(objNoTargetDir.c_str())) - { - objNoTargetDir = cmSystemTools::GetFilenameName(objNoTargetDir); - } - cmLocalUnixMakefileGenerator3::LocalObjectInfo& info = - this->LocalGenerator->LocalObjectFiles[objNoTargetDir]; - info.HasSourceExtension = hasSourceExtension; - info.push_back( - cmLocalUnixMakefileGenerator3::LocalObjectEntry(this->Target, lang) - ); + this->LocalGenerator->AddLocalObjectFile( + this->Target, &source, objNoTargetDir, hasSourceExtension); } //---------------------------------------------------------------------------- @@ -1069,6 +1061,35 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() << "SET(CMAKE_Fortran_TARGET_MODULE_DIR \"" << mdir << "\")\n"; } + // Target-specific include directories: + *this->InfoFileStream + << "\n" + << "# The include file search paths:\n"; + *this->InfoFileStream + << "SET(CMAKE_C_TARGET_INCLUDE_PATH\n"; + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->Target); + for(std::vector<std::string>::iterator i = includes.begin(); + i != includes.end(); ++i) + { + *this->InfoFileStream + << " \"" + << this->LocalGenerator->Convert(i->c_str(), + cmLocalGenerator::HOME_OUTPUT) + << "\"\n"; + } + *this->InfoFileStream + << " )\n"; + *this->InfoFileStream + << "SET(CMAKE_CXX_TARGET_INCLUDE_PATH " + << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; + *this->InfoFileStream + << "SET(CMAKE_Fortran_TARGET_INCLUDE_PATH " + << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; + *this->InfoFileStream + << "SET(CMAKE_ASM_TARGET_INCLUDE_PATH " + << "${CMAKE_C_TARGET_INCLUDE_PATH})\n"; + // and now write the rule to use it std::vector<std::string> depends; std::vector<std::string> commands; @@ -1534,7 +1555,7 @@ std::string cmMakefileTargetGenerator::GetFrameworkFlags() emitted.insert("/System/Library/Frameworks"); #endif std::vector<std::string> includes; - this->LocalGenerator->GetIncludeDirectories(includes); + this->LocalGenerator->GetIncludeDirectories(includes, this->Target); std::vector<std::string>::iterator i; // check all include directories for frameworks as this // will already have added a -F for the framework @@ -1829,8 +1850,12 @@ void cmMakefileTargetGenerator::AddIncludeFlags(std::string& flags, responseVar += "_USE_RESPONSE_FILE_FOR_INCLUDES"; bool useResponseFile = this->Makefile->IsOn(responseVar.c_str()); + + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->Target, lang); + std::string includeFlags = - this->LocalGenerator->GetIncludeFlags(lang, useResponseFile); + this->LocalGenerator->GetIncludeFlags(includes, lang, useResponseFile); if(includeFlags.empty()) { return; @@ -1930,7 +1955,7 @@ void cmMakefileTargetGenerator::AddFortranFlags(std::string& flags) this->Makefile->GetDefinition("CMAKE_Fortran_MODPATH_FLAG")) { std::vector<std::string> includes; - this->LocalGenerator->GetIncludeDirectories(includes); + this->LocalGenerator->GetIncludeDirectories(includes, this->Target); for(std::vector<std::string>::const_iterator idi = includes.begin(); idi != includes.end(); ++idi) { diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx new file mode 100644 index 0000000..9242181 --- /dev/null +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -0,0 +1,469 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmNinjaNormalTargetGenerator.h" +#include "cmLocalNinjaGenerator.h" +#include "cmGlobalNinjaGenerator.h" +#include "cmSourceFile.h" +#include "cmGeneratedFileStream.h" +#include "cmMakefile.h" + +#include <assert.h> + +cmNinjaNormalTargetGenerator:: +cmNinjaNormalTargetGenerator(cmTarget* target) + : cmNinjaTargetGenerator(target) + , TargetNameOut() + , TargetNameSO() + , TargetNameReal() + , TargetNameImport() + , TargetNamePDB() +{ + this->TargetLinkLanguage = target->GetLinkerLanguage(this->GetConfigName()); + if (target->GetType() == cmTarget::EXECUTABLE) + target->GetExecutableNames(this->TargetNameOut, + this->TargetNameReal, + this->TargetNameImport, + this->TargetNamePDB, + GetLocalGenerator()->GetConfigName()); + else + target->GetLibraryNames(this->TargetNameOut, + this->TargetNameSO, + this->TargetNameReal, + this->TargetNameImport, + this->TargetNamePDB, + GetLocalGenerator()->GetConfigName()); + + // on Windows the output dir is already needed at compile time + // ensure the directory exists (OutDir test) + std::string outpath = target->GetDirectory(this->GetConfigName()); + cmSystemTools::MakeDirectory(outpath.c_str()); +} + +cmNinjaNormalTargetGenerator::~cmNinjaNormalTargetGenerator() +{ +} + +void cmNinjaNormalTargetGenerator::Generate() +{ + if (!this->TargetLinkLanguage) { + cmSystemTools::Error("CMake can not determine linker language for target:", + this->GetTarget()->GetName()); + return; + } + + // Write the rules for each language. + this->WriteLanguagesRules(); + + // Write the build statements + this->WriteObjectBuildStatements(); + + this->WriteLinkRule(); + this->WriteLinkStatement(); + + this->GetBuildFileStream() << "\n"; + this->GetRulesFileStream() << "\n"; +} + +void cmNinjaNormalTargetGenerator::WriteLanguagesRules() +{ + cmGlobalNinjaGenerator::WriteDivider(this->GetRulesFileStream()); + this->GetRulesFileStream() + << "# Rules for each languages for " + << cmTarget::GetTargetTypeName(this->GetTarget()->GetType()) + << " target " + << this->GetTargetName() + << "\n\n"; + + std::set<cmStdString> languages; + this->GetTarget()->GetLanguages(languages); + for(std::set<cmStdString>::const_iterator l = languages.begin(); + l != languages.end(); + ++l) + this->WriteLanguageRules(*l); +} + +const char *cmNinjaNormalTargetGenerator::GetVisibleTypeName() const +{ + switch (this->GetTarget()->GetType()) { + case cmTarget::STATIC_LIBRARY: + return "static library"; + case cmTarget::SHARED_LIBRARY: + return "shared library"; + case cmTarget::MODULE_LIBRARY: + return "shared module"; + case cmTarget::EXECUTABLE: + return "executable"; + default: + return 0; + } +} + +std::string +cmNinjaNormalTargetGenerator +::LanguageLinkerRule() const +{ + return std::string(this->TargetLinkLanguage) + + "_" + + cmTarget::GetTargetTypeName(this->GetTarget()->GetType()) + + "_LINKER"; +} + +void +cmNinjaNormalTargetGenerator +::WriteLinkRule() +{ + cmTarget::TargetType targetType = this->GetTarget()->GetType(); + std::string ruleName = this->LanguageLinkerRule(); + + if (!this->GetGlobalGenerator()->HasRule(ruleName)) { + cmLocalGenerator::RuleVariables vars; + vars.RuleLauncher = "RULE_LAUNCH_LINK"; + vars.CMTarget = this->GetTarget(); + vars.Language = this->TargetLinkLanguage; + vars.Objects = "$in"; + std::string objdir = cmake::GetCMakeFilesDirectoryPostSlash(); + objdir += this->GetTargetName(); + objdir += ".dir"; + objdir = this->GetLocalGenerator()->Convert(objdir.c_str(), + cmLocalGenerator::START_OUTPUT, + cmLocalGenerator::SHELL); + vars.ObjectDir = objdir.c_str(); + vars.Target = "$out"; + vars.TargetSOName = "$SONAME"; + vars.TargetInstallNameDir = "$INSTALLNAME_DIR"; + vars.TargetPDB = "$TARGET_PDB"; + + // Setup the target version. + std::string targetVersionMajor; + std::string targetVersionMinor; + { + cmOStringStream majorStream; + cmOStringStream minorStream; + int major; + int minor; + this->GetTarget()->GetTargetVersion(major, minor); + majorStream << major; + minorStream << minor; + targetVersionMajor = majorStream.str(); + targetVersionMinor = minorStream.str(); + } + vars.TargetVersionMajor = targetVersionMajor.c_str(); + vars.TargetVersionMinor = targetVersionMinor.c_str(); + + vars.LinkLibraries = "$LINK_LIBRARIES"; + vars.Flags = "$FLAGS"; + vars.LinkFlags = "$LINK_FLAGS"; + + std::string langFlags; + this->GetLocalGenerator()->AddLanguageFlags(langFlags, + this->TargetLinkLanguage, + this->GetConfigName()); + if (targetType != cmTarget::EXECUTABLE) + langFlags += " $ARCH_FLAGS"; + vars.LanguageCompileFlags = langFlags.c_str(); + + // Rule for linking library. + std::vector<std::string> linkCmds = this->ComputeLinkCmd(); + for(std::vector<std::string>::iterator i = linkCmds.begin(); + i != linkCmds.end(); + ++i) + { + this->GetLocalGenerator()->ExpandRuleVariables(*i, vars); + } + linkCmds.insert(linkCmds.begin(), "$PRE_LINK"); + linkCmds.push_back("$POST_BUILD"); + std::string linkCmd = + this->GetLocalGenerator()->BuildCommandLine(linkCmds); + + // Write the linker rule. + std::ostringstream comment; + comment << "Rule for linking " << this->TargetLinkLanguage << " " + << this->GetVisibleTypeName() << "."; + std::ostringstream description; + description << "Linking " << this->TargetLinkLanguage << " " + << this->GetVisibleTypeName() << " $out"; + this->GetGlobalGenerator()->AddRule(ruleName, + linkCmd, + description.str(), + comment.str()); + } + + if (this->TargetNameOut != this->TargetNameReal) { + std::string cmakeCommand = + this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"), + cmLocalGenerator::SHELL); + if (targetType == cmTarget::EXECUTABLE) + this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_EXECUTABLE", + cmakeCommand + + " -E cmake_symlink_executable" + " $in $out && $POST_BUILD", + "Creating executable symlink $out", + "Rule for creating executable symlink."); + else + this->GetGlobalGenerator()->AddRule("CMAKE_SYMLINK_LIBRARY", + cmakeCommand + + " -E cmake_symlink_library" + " $in $SONAME $out && $POST_BUILD", + "Creating library symlink $out", + "Rule for creating library symlink."); + } +} + +std::vector<std::string> +cmNinjaNormalTargetGenerator +::ComputeLinkCmd() +{ + std::vector<std::string> linkCmds; + cmTarget::TargetType targetType = this->GetTarget()->GetType(); + switch (targetType) { + case cmTarget::STATIC_LIBRARY: { + // Check if you have a non archive way to create the static library. + { + std::string linkCmdVar = "CMAKE_"; + linkCmdVar += this->TargetLinkLanguage; + linkCmdVar += "_CREATE_STATIC_LIBRARY"; + if (const char *linkCmd = + this->GetMakefile()->GetDefinition(linkCmdVar.c_str())) + { + cmSystemTools::ExpandListArgument(linkCmd, linkCmds); + return linkCmds; + } + } + + // We have archive link commands set. First, delete the existing archive. + std::string cmakeCommand = + this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetMakefile()->GetRequiredDefinition("CMAKE_COMMAND"), + cmLocalGenerator::SHELL); + linkCmds.push_back(cmakeCommand + " -E remove $out"); + + // TODO: Use ARCHIVE_APPEND for archives over a certain size. + { + std::string linkCmdVar = "CMAKE_"; + linkCmdVar += this->TargetLinkLanguage; + linkCmdVar += "_ARCHIVE_CREATE"; + const char *linkCmd = + this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str()); + cmSystemTools::ExpandListArgument(linkCmd, linkCmds); + } + { + std::string linkCmdVar = "CMAKE_"; + linkCmdVar += this->TargetLinkLanguage; + linkCmdVar += "_ARCHIVE_FINISH"; + const char *linkCmd = + this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str()); + cmSystemTools::ExpandListArgument(linkCmd, linkCmds); + } + return linkCmds; + } + case cmTarget::SHARED_LIBRARY: + case cmTarget::MODULE_LIBRARY: + case cmTarget::EXECUTABLE: { + std::string linkCmdVar = "CMAKE_"; + linkCmdVar += this->TargetLinkLanguage; + switch (targetType) { + case cmTarget::SHARED_LIBRARY: + linkCmdVar += "_CREATE_SHARED_LIBRARY"; + break; + case cmTarget::MODULE_LIBRARY: + linkCmdVar += "_CREATE_SHARED_MODULE"; + break; + case cmTarget::EXECUTABLE: + linkCmdVar += "_LINK_EXECUTABLE"; + break; + default: + assert(0 && "Unexpected target type"); + } + + const char *linkCmd = + this->GetMakefile()->GetRequiredDefinition(linkCmdVar.c_str()); + cmSystemTools::ExpandListArgument(linkCmd, linkCmds); + return linkCmds; + } + default: + assert(0 && "Unexpected target type"); + } + return std::vector<std::string>(); +} + +void cmNinjaNormalTargetGenerator::WriteLinkStatement() +{ + cmTarget::TargetType targetType = this->GetTarget()->GetType(); + + // Write comments. + cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + this->GetBuildFileStream() + << "# Link build statements for " + << cmTarget::GetTargetTypeName(targetType) + << " target " + << this->GetTargetName() + << "\n\n"; + + cmNinjaDeps emptyDeps; + cmNinjaVars vars; + + std::string targetOutput = ConvertToNinjaPath( + this->GetTarget()->GetFullPath(this->GetConfigName()).c_str()); + std::string targetOutputReal = ConvertToNinjaPath( + this->GetTarget()->GetFullPath(this->GetConfigName(), + /*implib=*/false, + /*realpath=*/true).c_str()); + std::string targetOutputImplib = ConvertToNinjaPath( + this->GetTarget()->GetFullPath(this->GetConfigName(), + /*implib=*/true).c_str()); + + // Compute the comment. + std::ostringstream comment; + comment << "Link the " << this->GetVisibleTypeName() << " " + << targetOutputReal; + + // Compute outputs. + cmNinjaDeps outputs; + outputs.push_back(targetOutputReal); + + // Compute specific libraries to link with. + cmNinjaDeps explicitDeps = this->GetObjects(), + implicitDeps = this->ComputeLinkDeps(); + + this->GetLocalGenerator()->GetTargetFlags(vars["LINK_LIBRARIES"], + vars["FLAGS"], + vars["LINK_FLAGS"], + *this->GetTarget()); + + this->AddModuleDefinitionFlag(vars["LINK_FLAGS"]); + + // Compute architecture specific link flags. Yes, these go into a different + // variable for executables, probably due to a mistake made when duplicating + // code between the Makefile executable and library generators. + this->GetLocalGenerator() + ->AddArchitectureFlags(targetType == cmTarget::EXECUTABLE + ? vars["FLAGS"] + : vars["ARCH_FLAGS"], + this->GetTarget(), + this->TargetLinkLanguage, + this->GetConfigName()); + vars["SONAME"] = this->TargetNameSO; + + if (targetType == cmTarget::SHARED_LIBRARY) { + std::string install_name_dir = + this->GetTarget()->GetInstallNameDirForBuildTree(this->GetConfigName()); + + if (!install_name_dir.empty()) { + vars["INSTALLNAME_DIR"] = + this->GetLocalGenerator()->Convert(install_name_dir.c_str(), + cmLocalGenerator::NONE, + cmLocalGenerator::SHELL, false); + } + } + + if (!this->TargetNameImport.empty()) { + vars["TARGET_IMPLIB"] = this->GetLocalGenerator()->ConvertToOutputFormat( + targetOutputImplib.c_str(), cmLocalGenerator::SHELL); + } + + vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL); + + std::vector<cmCustomCommand> *cmdLists[3] = { + &this->GetTarget()->GetPreBuildCommands(), + &this->GetTarget()->GetPreLinkCommands(), + &this->GetTarget()->GetPostBuildCommands() + }; + + std::vector<std::string> preLinkCmdLines, postBuildCmdLines; + std::vector<std::string> *cmdLineLists[3] = { + &preLinkCmdLines, + &preLinkCmdLines, + &postBuildCmdLines + }; + + for (unsigned i = 0; i != 3; ++i) { + for (std::vector<cmCustomCommand>::const_iterator + ci = cmdLists[i]->begin(); + ci != cmdLists[i]->end(); ++ci) { + this->GetLocalGenerator()->AppendCustomCommandLines(&*ci, + *cmdLineLists[i]); + } + } + + // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for + // the link commands. + if (!preLinkCmdLines.empty()) { + std::string path = this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetMakefile()->GetHomeOutputDirectory(), + cmLocalGenerator::SHELL); + preLinkCmdLines.push_back("cd " + path); + } + + vars["PRE_LINK"] = + this->GetLocalGenerator()->BuildCommandLine(preLinkCmdLines); + std::string postBuildCmdLine = + this->GetLocalGenerator()->BuildCommandLine(postBuildCmdLines); + + cmNinjaVars symlinkVars; + if (targetOutput == targetOutputReal) { + vars["POST_BUILD"] = postBuildCmdLine; + } else { + vars["POST_BUILD"] = ":"; + symlinkVars["POST_BUILD"] = postBuildCmdLine; + } + + // Write the build statement for this target. + cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + comment.str(), + this->LanguageLinkerRule(), + outputs, + explicitDeps, + implicitDeps, + emptyDeps, + vars); + + if (targetOutput != targetOutputReal) { + if (targetType == cmTarget::EXECUTABLE) { + cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + "Create executable symlink " + targetOutput, + "CMAKE_SYMLINK_EXECUTABLE", + cmNinjaDeps(1, targetOutput), + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); + } else { + symlinkVars["SONAME"] = this->GetTargetFilePath(this->TargetNameSO); + cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + "Create library symlink " + targetOutput, + "CMAKE_SYMLINK_LIBRARY", + cmNinjaDeps(1, targetOutput), + cmNinjaDeps(1, targetOutputReal), + emptyDeps, + emptyDeps, + symlinkVars); + } + } + + if (!this->TargetNameImport.empty()) { + // Since using multiple outputs would mess up the $out variable, use an + // alias for the import library. + cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), + "Alias for import library.", + cmNinjaDeps(1, targetOutputImplib), + cmNinjaDeps(1, targetOutputReal)); + } + + // Add aliases for the file name and the target name. + this->GetGlobalGenerator()->AddTargetAlias(this->TargetNameOut, + this->GetTarget()); + this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), + this->GetTarget()); +} diff --git a/Source/cmNinjaNormalTargetGenerator.h b/Source/cmNinjaNormalTargetGenerator.h new file mode 100644 index 0000000..99f5a13 --- /dev/null +++ b/Source/cmNinjaNormalTargetGenerator.h @@ -0,0 +1,47 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmNinjaNormalTargetGenerator_h +# define cmNinjaNormalTargetGenerator_h + +# include "cmNinjaTargetGenerator.h" +# include "cmNinjaTypes.h" + +class cmSourceFile; + +class cmNinjaNormalTargetGenerator : public cmNinjaTargetGenerator +{ +public: + cmNinjaNormalTargetGenerator(cmTarget* target); + ~cmNinjaNormalTargetGenerator(); + + void Generate(); + +private: + std::string LanguageLinkerRule() const; + const char* GetVisibleTypeName() const; + void WriteLanguagesRules(); + void WriteLinkRule(); + void WriteLinkStatement(); + std::vector<std::string> ComputeLinkCmd(); + +private: + // Target name info. + std::string TargetNameOut; + std::string TargetNameSO; + std::string TargetNameReal; + std::string TargetNameImport; + std::string TargetNamePDB; + const char *TargetLinkLanguage; +}; + +#endif // ! cmNinjaNormalTargetGenerator_h diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx new file mode 100644 index 0000000..9acbc67 --- /dev/null +++ b/Source/cmNinjaTargetGenerator.cxx @@ -0,0 +1,515 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmNinjaTargetGenerator.h" +#include "cmGlobalNinjaGenerator.h" +#include "cmLocalNinjaGenerator.h" +#include "cmGeneratedFileStream.h" +#include "cmNinjaNormalTargetGenerator.h" +#include "cmNinjaUtilityTargetGenerator.h" +#include "cmSystemTools.h" +#include "cmMakefile.h" +#include "cmComputeLinkInformation.h" +#include "cmSourceFile.h" +#include "cmCustomCommandGenerator.h" + +#include <algorithm> + +cmNinjaTargetGenerator * +cmNinjaTargetGenerator::New(cmTarget* target) +{ + switch (target->GetType()) + { + case cmTarget::EXECUTABLE: + case cmTarget::SHARED_LIBRARY: + case cmTarget::STATIC_LIBRARY: + case cmTarget::MODULE_LIBRARY: + return new cmNinjaNormalTargetGenerator(target); + + case cmTarget::UTILITY: + return new cmNinjaUtilityTargetGenerator(target);; + + case cmTarget::GLOBAL_TARGET: { + // We only want to process global targets that live in the home + // (i.e. top-level) directory. CMake creates copies of these targets + // in every directory, which we don't need. + cmMakefile *mf = target->GetMakefile(); + if (strcmp(mf->GetStartDirectory(), mf->GetHomeDirectory()) == 0) + return new cmNinjaUtilityTargetGenerator(target); + // else fallthrough + } + + default: + return 0; + } +} + +cmNinjaTargetGenerator::cmNinjaTargetGenerator(cmTarget* target) + : Target(target), + Makefile(target->GetMakefile()), + LocalGenerator( + static_cast<cmLocalNinjaGenerator*>(Makefile->GetLocalGenerator())), + Objects() +{ +} + +cmNinjaTargetGenerator::~cmNinjaTargetGenerator() +{ +} + +cmGeneratedFileStream& cmNinjaTargetGenerator::GetBuildFileStream() const +{ + return *this->GetGlobalGenerator()->GetBuildFileStream(); +} + +cmGeneratedFileStream& cmNinjaTargetGenerator::GetRulesFileStream() const +{ + return *this->GetGlobalGenerator()->GetRulesFileStream(); +} + +cmGlobalNinjaGenerator* cmNinjaTargetGenerator::GetGlobalGenerator() const +{ + return this->LocalGenerator->GetGlobalNinjaGenerator(); +} + +const char* cmNinjaTargetGenerator::GetConfigName() const +{ + return this->LocalGenerator->ConfigName.c_str(); +} + +// TODO: Picked up from cmMakefileTargetGenerator. Refactor it. +const char* cmNinjaTargetGenerator::GetFeature(const char* feature) +{ + return this->Target->GetFeature(feature, this->GetConfigName()); +} + +// TODO: Picked up from cmMakefileTargetGenerator. Refactor it. +bool cmNinjaTargetGenerator::GetFeatureAsBool(const char* feature) +{ + return cmSystemTools::IsOn(this->GetFeature(feature)); +} + +// TODO: Picked up from cmMakefileTargetGenerator. Refactor it. +void cmNinjaTargetGenerator::AddFeatureFlags(std::string& flags, + const char* lang) +{ + // Add language-specific flags. + this->LocalGenerator->AddLanguageFlags(flags, lang, this->GetConfigName()); + + if(this->GetFeatureAsBool("INTERPROCEDURAL_OPTIMIZATION")) + { + this->LocalGenerator->AppendFeatureOptions(flags, lang, "IPO"); + } +} + +// TODO: Most of the code is picked up from +// void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink), +// void cmMakefileTargetGenerator::WriteTargetLanguageFlags() +// Refactor it. +std::string +cmNinjaTargetGenerator::ComputeFlagsForObject(cmSourceFile *source, + const std::string& language) +{ + std::string flags; + + this->AddFeatureFlags(flags, language.c_str()); + + this->GetLocalGenerator()->AddArchitectureFlags(flags, + this->GetTarget(), + language.c_str(), + this->GetConfigName()); + + // TODO: Fortran support. + // // Fortran-specific flags computed for this target. + // if(*l == "Fortran") + // { + // this->AddFortranFlags(flags); + // } + + // Add shared-library flags if needed. + { + bool shared = ((this->Target->GetType() == cmTarget::SHARED_LIBRARY) || + (this->Target->GetType() == cmTarget::MODULE_LIBRARY)); + this->GetLocalGenerator()->AddSharedFlags(flags, language.c_str(), shared); + } + + // TODO: Handle response file. + // Add include directory flags. + { + std::vector<std::string> includes; + this->LocalGenerator->GetIncludeDirectories(includes, this->Target, + language.c_str()); + std::string includeFlags = + this->LocalGenerator->GetIncludeFlags(includes, language.c_str(), false); + this->LocalGenerator->AppendFlags(flags, includeFlags.c_str()); + } + + // Append old-style preprocessor definition flags. + this->LocalGenerator->AppendFlags(flags, this->Makefile->GetDefineFlags()); + + // Add target-specific and source-specific flags. + this->LocalGenerator->AppendFlags(flags, + this->Target->GetProperty("COMPILE_FLAGS")); + this->LocalGenerator->AppendFlags(flags, + source->GetProperty("COMPILE_FLAGS")); + + // TODO: Handle Apple frameworks. + + return flags; +} + +// TODO: Refactor with +// void cmMakefileTargetGenerator::WriteTargetLanguageFlags(). +std::string +cmNinjaTargetGenerator:: +ComputeDefines(cmSourceFile *source, const std::string& language) +{ + std::string defines; + + // Add the export symbol definition for shared library objects. + if(const char* exportMacro = this->Target->GetExportMacro()) + { + this->LocalGenerator->AppendDefines(defines, exportMacro, + language.c_str()); + } + + // Add preprocessor definitions for this target and configuration. + this->LocalGenerator->AppendDefines + (defines, + this->Makefile->GetProperty("COMPILE_DEFINITIONS"), + language.c_str()); + this->LocalGenerator->AppendDefines + (defines, + this->Target->GetProperty("COMPILE_DEFINITIONS"), + language.c_str()); + this->LocalGenerator->AppendDefines + (defines, + source->GetProperty("COMPILE_DEFINITIONS"), + language.c_str()); + { + std::string defPropName = "COMPILE_DEFINITIONS_"; + defPropName += cmSystemTools::UpperCase(this->GetConfigName()); + this->LocalGenerator->AppendDefines + (defines, + this->Makefile->GetProperty(defPropName.c_str()), + language.c_str()); + this->LocalGenerator->AppendDefines + (defines, + this->Target->GetProperty(defPropName.c_str()), + language.c_str()); + this->LocalGenerator->AppendDefines + (defines, + source->GetProperty(defPropName.c_str()), + language.c_str()); + } + + return defines; +} + +cmNinjaDeps cmNinjaTargetGenerator::ComputeLinkDeps() const +{ + // Static libraries never depend on other targets for linking. + if (this->Target->GetType() == cmTarget::STATIC_LIBRARY) + return cmNinjaDeps(); + + cmComputeLinkInformation* cli = + this->Target->GetLinkInformation(this->GetConfigName()); + if(!cli) + return cmNinjaDeps(); + + const std::vector<std::string> &deps = cli->GetDepends(); + cmNinjaDeps result(deps.size()); + std::transform(deps.begin(), deps.end(), result.begin(), MapToNinjaPath()); + + // Add a dependency on the link definitions file, if any. + if(!this->ModuleDefinitionFile.empty()) + { + result.push_back(this->ModuleDefinitionFile); + } + + return result; +} + +std::string +cmNinjaTargetGenerator +::GetSourceFilePath(cmSourceFile* source) const +{ + return ConvertToNinjaPath(source->GetFullPath().c_str()); +} + +std::string +cmNinjaTargetGenerator +::GetObjectFilePath(cmSourceFile* source) const +{ + std::string path = this->LocalGenerator->GetHomeRelativeOutputPath(); + if(!path.empty()) + path += "/"; + path += this->LocalGenerator->GetObjectFileName(*this->Target, *source); + return path; +} + +std::string cmNinjaTargetGenerator::GetTargetOutputDir() const +{ + std::string dir = this->Target->GetDirectory(this->GetConfigName()); + return ConvertToNinjaPath(dir.c_str()); +} + +std::string +cmNinjaTargetGenerator +::GetTargetFilePath(const std::string& name) const +{ + std::string path = this->GetTargetOutputDir(); + if (path.empty() || path == ".") + return name; + path += "/"; + path += name; + return path; +} + +std::string cmNinjaTargetGenerator::GetTargetName() const +{ + return this->Target->GetName(); +} + +std::string cmNinjaTargetGenerator::GetTargetPDB() const +{ + std::string targetFullPathPDB; + if(this->Target->GetType() == cmTarget::EXECUTABLE || + this->Target->GetType() == cmTarget::STATIC_LIBRARY || + this->Target->GetType() == cmTarget::SHARED_LIBRARY || + this->Target->GetType() == cmTarget::MODULE_LIBRARY) + { + targetFullPathPDB = this->Target->GetDirectory(this->GetConfigName()); + targetFullPathPDB += "/"; + targetFullPathPDB += this->Target->GetPDBName(this->GetConfigName()); + } + + return ConvertToNinjaPath(targetFullPathPDB.c_str()); +} + + +void +cmNinjaTargetGenerator +::WriteLanguageRules(const std::string& language) +{ + this->GetRulesFileStream() + << "# Rules for language " << language << "\n\n"; + this->WriteCompileRule(language); + this->GetRulesFileStream() << "\n"; +} + +void +cmNinjaTargetGenerator +::WriteCompileRule(const std::string& language) +{ + cmLocalGenerator::RuleVariables vars; + vars.RuleLauncher = "RULE_LAUNCH_COMPILE"; + vars.CMTarget = this->GetTarget(); + std::string lang = language; + vars.Language = lang.c_str(); + vars.Source = "$in"; + vars.Object = "$out"; + std::string flags = "$FLAGS"; + vars.Defines = "$DEFINES"; + vars.TargetPDB = "$TARGET_PDB"; + + std::string depfile; + std::string depfileFlagsName = "CMAKE_DEPFILE_FLAGS_" + language; + const char *depfileFlags = + this->GetMakefile()->GetDefinition(depfileFlagsName.c_str()); + if (depfileFlags) { + std::string depfileFlagsStr = depfileFlags; + depfile = "$out.d"; + cmSystemTools::ReplaceString(depfileFlagsStr, "<DEPFILE>", + depfile.c_str()); + flags += " " + depfileFlagsStr; + } + vars.Flags = flags.c_str(); + + + // Rule for compiling object file. + std::string compileCmdVar = "CMAKE_"; + compileCmdVar += language; + compileCmdVar += "_COMPILE_OBJECT"; + std::string compileCmd = + this->GetMakefile()->GetRequiredDefinition(compileCmdVar.c_str()); + std::vector<std::string> compileCmds; + cmSystemTools::ExpandListArgument(compileCmd, compileCmds); + + for (std::vector<std::string>::iterator i = compileCmds.begin(); + i != compileCmds.end(); ++i) + this->GetLocalGenerator()->ExpandRuleVariables(*i, vars); + + std::string cmdLine = + this->GetLocalGenerator()->BuildCommandLine(compileCmds); + + // Write the rule for compiling file of the given language. + std::ostringstream comment; + comment << "Rule for compiling " << language << " files."; + std::ostringstream description; + description << "Building " << language << " object $out"; + this->GetGlobalGenerator()->AddRule(this->LanguageCompilerRule(language), + cmdLine, + description.str(), + comment.str(), + depfile); +} + +void +cmNinjaTargetGenerator +::WriteObjectBuildStatements() +{ + // Write comments. + cmGlobalNinjaGenerator::WriteDivider(this->GetBuildFileStream()); + this->GetBuildFileStream() + << "# Object build statements for " + << cmTarget::GetTargetTypeName(this->GetTarget()->GetType()) + << " target " + << this->GetTargetName() + << "\n\n"; + + // For each source files of this target. + for(std::vector<cmSourceFile*>::const_iterator i = + this->GetTarget()->GetSourceFiles().begin(); + i != this->GetTarget()->GetSourceFiles().end(); + ++i) + this->WriteObjectBuildStatement(*i); + + this->GetBuildFileStream() << "\n"; +} + +void +cmNinjaTargetGenerator +::WriteObjectBuildStatement(cmSourceFile* source) +{ + if (cmCustomCommand *cc = source->GetCustomCommand()) + this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget()); + + cmNinjaDeps emptyDeps; + + std::string comment; + const char* language = source->GetLanguage(); + // If we cannot get the language this is probably a non-source file provided + // in the list (typically an header file). + if (!language) { + if (source->GetPropertyAsBool("EXTERNAL_OBJECT")) + this->Objects.push_back(this->GetSourceFilePath(source)); + if(cmSystemTools::UpperCase(source->GetExtension()) == "DEF") + this->ModuleDefinitionFile = GetSourceFilePath(source); + return; + } + + if (source->GetPropertyAsBool("HEADER_FILE_ONLY")) + return; + + std::string rule = this->LanguageCompilerRule(language); + + cmNinjaDeps outputs; + std::string objectFileName = this->GetObjectFilePath(source); + outputs.push_back(objectFileName); + // Add this object to the list of object files. + this->Objects.push_back(objectFileName); + + cmNinjaDeps explicitDeps; + std::string sourceFileName = this->GetSourceFilePath(source); + explicitDeps.push_back(sourceFileName); + + // Ensure that the target dependencies are built before any source file in + // the target, using order-only dependencies. + cmNinjaDeps orderOnlyDeps; + this->GetLocalGenerator()->AppendTargetDepends(this->Target, orderOnlyDeps); + + if(const char* objectDeps = source->GetProperty("OBJECT_DEPENDS")) { + std::vector<std::string> depList; + cmSystemTools::ExpandListArgument(objectDeps, depList); + std::transform(depList.begin(), depList.end(), + std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + } + + // Add order-only dependency on any header file with a custom command. + { + const std::vector<cmSourceFile*>& sources = + this->GetTarget()->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator si = sources.begin(); + si != sources.end(); ++si) { + if (!(*si)->GetLanguage()) { + if (cmCustomCommand* cc = (*si)->GetCustomCommand()) { + const std::vector<std::string>& ccoutputs = cc->GetOutputs(); + std::transform(ccoutputs.begin(), ccoutputs.end(), + std::back_inserter(orderOnlyDeps), MapToNinjaPath()); + } + } + } + } + + // If the source file is GENERATED and does not have a custom command + // (either attached to this source file or another one), assume that one of + // the target dependencies, OBJECT_DEPENDS or header file custom commands + // will rebuild the file. + if (source->GetPropertyAsBool("GENERATED") && !source->GetCustomCommand() && + !this->GetGlobalGenerator()->HasCustomCommandOutput(sourceFileName)) { + this->GetGlobalGenerator()->AddAssumedSourceDependencies(sourceFileName, + orderOnlyDeps); + } + + cmNinjaVars vars; + vars["FLAGS"] = this->ComputeFlagsForObject(source, language); + vars["DEFINES"] = this->ComputeDefines(source, language); + vars["TARGET_PDB"] = this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetTargetPDB().c_str(), cmLocalGenerator::SHELL); + + cmGlobalNinjaGenerator::WriteBuild(this->GetBuildFileStream(), + comment, + rule, + outputs, + explicitDeps, + emptyDeps, + orderOnlyDeps, + vars); + + if(const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { + std::vector<std::string> outputList; + cmSystemTools::ExpandListArgument(objectOutputs, outputList); + std::transform(outputList.begin(), outputList.end(), outputList.begin(), + MapToNinjaPath()); + cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), + "Additional output files.", + outputList, + outputs); + } +} + +//---------------------------------------------------------------------------- +void +cmNinjaTargetGenerator +::AddModuleDefinitionFlag(std::string& flags) +{ + if(this->ModuleDefinitionFile.empty()) + { + return; + } + + // TODO: Create a per-language flag variable. + const char* defFileFlag = + this->Makefile->GetDefinition("CMAKE_LINK_DEF_FILE_FLAG"); + if(!defFileFlag) + { + return; + } + + // Append the flag and value. Use ConvertToLinkReference to help + // vs6's "cl -link" pass it to the linker. + std::string flag = defFileFlag; + flag += (this->LocalGenerator->ConvertToLinkReference( + this->ModuleDefinitionFile.c_str())); + this->LocalGenerator->AppendFlags(flags, flag.c_str()); +} diff --git a/Source/cmNinjaTargetGenerator.h b/Source/cmNinjaTargetGenerator.h new file mode 100644 index 0000000..3e70a2c --- /dev/null +++ b/Source/cmNinjaTargetGenerator.h @@ -0,0 +1,124 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmNinjaTargetGenerator_h +#define cmNinjaTargetGenerator_h + +#include "cmStandardIncludes.h" +#include "cmNinjaTypes.h" +#include "cmLocalNinjaGenerator.h" + +class cmTarget; +class cmGlobalNinjaGenerator; +class cmGeneratedFileStream; +class cmMakefile; +class cmSourceFile; +class cmCustomCommand; + +class cmNinjaTargetGenerator +{ +public: + /// Create a cmNinjaTargetGenerator according to the @a target's type. + static cmNinjaTargetGenerator* New(cmTarget* target); + + /// Build a NinjaTargetGenerator. + cmNinjaTargetGenerator(cmTarget* target); + + /// Destructor. + virtual ~cmNinjaTargetGenerator(); + + virtual void Generate() = 0; + + std::string GetTargetPDB() const; + std::string GetTargetName() const; + +protected: + cmGeneratedFileStream& GetBuildFileStream() const; + cmGeneratedFileStream& GetRulesFileStream() const; + + cmTarget* GetTarget() const + { return this->Target; } + + cmLocalNinjaGenerator* GetLocalGenerator() const + { return this->LocalGenerator; } + + cmGlobalNinjaGenerator* GetGlobalGenerator() const; + + cmMakefile* GetMakefile() const + { return this->Makefile; } + + const char* GetConfigName() const; + + std::string LanguageCompilerRule(const std::string& lang) const + { return lang + "_COMPILER"; } + + const char* GetFeature(const char* feature); + bool GetFeatureAsBool(const char* feature); + void AddFeatureFlags(std::string& flags, const char* lang); + + /** + * Compute the flags for compilation of object files for a given @a language. + * @note Generally it is the value of the variable whose name is computed + * by LanguageFlagsVarName(). + */ + std::string ComputeFlagsForObject(cmSourceFile *source, + const std::string& language); + + std::string ComputeDefines(cmSourceFile *source, + const std::string& language); + + std::string ConvertToNinjaPath(const char *path) const { + return this->GetLocalGenerator()->ConvertToNinjaPath(path); + } + cmLocalNinjaGenerator::map_to_ninja_path MapToNinjaPath() const { + return this->GetLocalGenerator()->MapToNinjaPath(); + } + + /// @return the list of link dependency for the given target @a target. + cmNinjaDeps ComputeLinkDeps() const; + + /// @return the source file path for the given @a source. + std::string GetSourceFilePath(cmSourceFile* source) const; + + /// @return the object file path for the given @a source. + std::string GetObjectFilePath(cmSourceFile* source) const; + + /// @return the file path where the target named @a name is generated. + std::string GetTargetFilePath(const std::string& name) const; + + /// @return the output path for the target. + virtual std::string GetTargetOutputDir() const; + + void WriteLanguageRules(const std::string& language); + void WriteCompileRule(const std::string& language); + void WriteObjectBuildStatements(); + void WriteObjectBuildStatement(cmSourceFile* source); + void WriteCustomCommandBuildStatement(cmCustomCommand *cc); + + cmNinjaDeps GetObjects() const + { return this->Objects; } + + // Helper to add flag for windows .def file. + void AddModuleDefinitionFlag(std::string& flags); + +private: + cmTarget* Target; + cmMakefile* Makefile; + cmLocalNinjaGenerator* LocalGenerator; + /// List of object files for this target. + cmNinjaDeps Objects; + + // The windows module definition source file (.def), if any. + std::string ModuleDefinitionFile; +}; + +#endif // ! cmNinjaTargetGenerator_h diff --git a/Source/cmNinjaTypes.h b/Source/cmNinjaTypes.h new file mode 100644 index 0000000..498f6b6 --- /dev/null +++ b/Source/cmNinjaTypes.h @@ -0,0 +1,19 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmNinjaTypes_h +# define cmNinjaTypes_h + +typedef std::vector<std::string> cmNinjaDeps; +typedef std::map<std::string, std::string> cmNinjaVars; + +#endif // ! cmNinjaTypes_h diff --git a/Source/cmNinjaUtilityTargetGenerator.cxx b/Source/cmNinjaUtilityTargetGenerator.cxx new file mode 100644 index 0000000..9c2fd13 --- /dev/null +++ b/Source/cmNinjaUtilityTargetGenerator.cxx @@ -0,0 +1,116 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmNinjaUtilityTargetGenerator.h" +#include "cmCustomCommand.h" +#include "cmGeneratedFileStream.h" +#include "cmGlobalNinjaGenerator.h" +#include "cmMakefile.h" +#include "cmSourceFile.h" +#include "cmTarget.h" + +cmNinjaUtilityTargetGenerator::cmNinjaUtilityTargetGenerator(cmTarget *target) + : cmNinjaTargetGenerator(target) {} + +cmNinjaUtilityTargetGenerator::~cmNinjaUtilityTargetGenerator() {} + +void cmNinjaUtilityTargetGenerator::Generate() +{ + std::vector<std::string> commands; + cmNinjaDeps deps, outputs; + + const std::vector<cmCustomCommand> *cmdLists[2] = { + &this->GetTarget()->GetPreBuildCommands(), + &this->GetTarget()->GetPostBuildCommands() + }; + + for (unsigned i = 0; i != 2; ++i) { + for (std::vector<cmCustomCommand>::const_iterator + ci = cmdLists[i]->begin(); ci != cmdLists[i]->end(); ++ci) { + this->GetLocalGenerator()->AppendCustomCommandDeps(&*ci, deps); + this->GetLocalGenerator()->AppendCustomCommandLines(&*ci, commands); + } + } + + const std::vector<cmSourceFile*>& sources = + this->GetTarget()->GetSourceFiles(); + for(std::vector<cmSourceFile*>::const_iterator source = sources.begin(); + source != sources.end(); ++source) + { + if(cmCustomCommand* cc = (*source)->GetCustomCommand()) + { + this->GetLocalGenerator()->AddCustomCommandTarget(cc, this->GetTarget()); + + // Depend on all custom command outputs. + const std::vector<std::string>& ccOutputs = cc->GetOutputs(); + std::transform(ccOutputs.begin(), ccOutputs.end(), + std::back_inserter(deps), MapToNinjaPath()); + } + } + + this->GetLocalGenerator()->AppendTargetOutputs(this->GetTarget(), outputs); + this->GetLocalGenerator()->AppendTargetDepends(this->GetTarget(), deps); + + if (commands.empty()) { + cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), + "Utility command for " + + this->GetTargetName(), + outputs, + deps); + } else { + std::string command = + this->GetLocalGenerator()->BuildCommandLine(commands); + const char *echoStr = this->GetTarget()->GetProperty("EchoString"); + std::string desc; + if (echoStr) + desc = echoStr; + else + desc = "Running utility command for " + this->GetTargetName(); + + // TODO: fix problematic global targets. For now, search and replace the + // makefile vars. + cmSystemTools::ReplaceString( + command, + "$(CMAKE_SOURCE_DIR)", + this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetTarget()->GetMakefile()->GetHomeDirectory(), + cmLocalGenerator::SHELL).c_str()); + cmSystemTools::ReplaceString( + command, + "$(CMAKE_BINARY_DIR)", + this->GetLocalGenerator()->ConvertToOutputFormat( + this->GetTarget()->GetMakefile()->GetHomeOutputDirectory(), + cmLocalGenerator::SHELL).c_str()); + cmSystemTools::ReplaceString(command, "$(ARGS)", ""); + + if (command.find('$') != std::string::npos) + return; + + std::string utilCommandName = cmake::GetCMakeFilesDirectoryPostSlash(); + utilCommandName += this->GetTargetName() + ".util"; + + this->GetGlobalGenerator()->WriteCustomCommandBuild( + command, + desc, + "Utility command for " + this->GetTargetName(), + cmNinjaDeps(1, utilCommandName), + deps); + + cmGlobalNinjaGenerator::WritePhonyBuild(this->GetBuildFileStream(), + "", + outputs, + cmNinjaDeps(1, utilCommandName)); + } + + this->GetGlobalGenerator()->AddTargetAlias(this->GetTargetName(), + this->GetTarget()); +} diff --git a/Source/cmNinjaUtilityTargetGenerator.h b/Source/cmNinjaUtilityTargetGenerator.h new file mode 100644 index 0000000..8b82ce4 --- /dev/null +++ b/Source/cmNinjaUtilityTargetGenerator.h @@ -0,0 +1,30 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2011 Peter Collingbourne <peter@pcc.me.uk> + Copyright 2011 Nicolas Despres <nicolas.despres@gmail.com> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmNinjaUtilityTargetGenerator_h +# define cmNinjaUtilityTargetGenerator_h + +# include "cmNinjaTargetGenerator.h" +# include "cmNinjaTypes.h" + +class cmSourceFile; + +class cmNinjaUtilityTargetGenerator : public cmNinjaTargetGenerator +{ +public: + cmNinjaUtilityTargetGenerator(cmTarget* target); + ~cmNinjaUtilityTargetGenerator(); + + void Generate(); +}; + +#endif // ! cmNinjaUtilityTargetGenerator_h diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 15e689b..1376a48 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -198,6 +198,20 @@ std::string cmSystemTools::EscapeQuotes(const char* str) return result; } +std::string cmSystemTools::TrimWhitespace(const std::string& s) +{ + std::string::const_iterator start = s.begin(); + while(start != s.end() && *start == ' ') + ++start; + if (start == s.end()) + return ""; + + std::string::const_iterator stop = s.end()-1; + while(*stop == ' ') + --stop; + return std::string(start, stop+1); +} + void cmSystemTools::Error(const char* m1, const char* m2, const char* m3, const char* m4) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 7afc701..5f21de2 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -49,6 +49,11 @@ public: ///! Escape quotes in a string. static std::string EscapeQuotes(const char* str); + /** + * Returns a string that has whitespace removed from the start and the end. + */ + static std::string TrimWhitespace(const std::string& s); + typedef void (*ErrorCallback)(const char*, const char*, bool&, void*); /** * Set the function used by GUI's to display error messages diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index da99eb9..2fbca80 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -480,6 +480,26 @@ void cmTarget::DefineProperties(cmake *cm) "undefined behavior."); cm->DefineProperty + ("INCLUDE_DIRECTORIES", cmProperty::TARGET, + "List of preprocessor include file search directories.", + "This property specifies the list of directories given " + "so far to the include_directories command. " + "This property exists on directories and targets. " + "In addition to accepting values from the include_directories " + "command, values may be set directly on any directory or any " + "target using the set_property command. " + "A target gets its initial value for this property from the value " + "of the directory property. " + "A directory gets its initial value from its parent directory if " + "it has one. " + "Both directory and target property values are adjusted by calls " + "to the include_directories command." + "\n" + "The target property values are used by the generators to set " + "the include paths for the compiler. " + "See also the include_directories command."); + + cm->DefineProperty ("INSTALL_NAME_DIR", cmProperty::TARGET, "Mac OSX directory name for installed targets.", "INSTALL_NAME_DIR is a string specifying the " @@ -861,7 +881,9 @@ void cmTarget::DefineProperties(cmake *cm) "of of just main()." "This makes it a GUI executable instead of a console application. " "See the CMAKE_MFC_FLAG variable documentation to configure use " - "of MFC for WinMain executables."); + "of MFC for WinMain executables. " + "This property is initialized by the value of the variable " + "CMAKE_WIN32_EXECUTABLE if it is set when a target is created."); cm->DefineProperty ("MACOSX_BUNDLE", cmProperty::TARGET, @@ -871,7 +893,9 @@ void cmTarget::DefineProperties(cmake *cm) "This makes it a GUI executable that can be launched from " "the Finder. " "See the MACOSX_BUNDLE_INFO_PLIST target property for information " - "about creation of the Info.plist file for the application bundle."); + "about creation of the Info.plist file for the application bundle. " + "This property is initialized by the value of the variable " + "CMAKE_MACOSX_BUNDLE if it is set when a target is created."); cm->DefineProperty ("MACOSX_BUNDLE_INFO_PLIST", cmProperty::TARGET, @@ -958,7 +982,12 @@ void cmTarget::DefineProperties(cmake *cm) "When this property is not set the modules will be placed in the " "build directory corresponding to the target's source directory. " "If the variable CMAKE_Fortran_MODULE_DIRECTORY is set when a target " - "is created its value is used to initialize this property."); + "is created its value is used to initialize this property." + "\n" + "Note that some compilers will automatically search the module output " + "directory for modules USEd during compilation but others will not. " + "If your sources USE modules their location must be specified by " + "INCLUDE_DIRECTORIES regardless of this property."); cm->DefineProperty ("GNUtoMS", cmProperty::TARGET, @@ -1077,17 +1106,6 @@ void cmTarget::DefineProperties(cmake *cm) "better if VS_GLOBAL_QtVersion is set to the version " "FindQt4.cmake found. For example, \"4.7.3\""); -#if 0 - cm->DefineProperty - ("OBJECT_FILES", cmProperty::TARGET, - "Used to get the resulting list of object files that make up a " - "target.", - "This can be used to put object files from one library " - "into another library. It is a read only property. It " - "converts the source list for the target into a list of full " - "paths to object names that will be produced by the target."); -#endif - #define CM_TARGET_FILE_TYPES_DOC \ "There are three kinds of target files that may be built: " \ "archive, library, and runtime. " \ @@ -1224,6 +1242,8 @@ void cmTarget::SetMakefile(cmMakefile* mf) this->SetPropertyDefault("AUTOMOC", 0); this->SetPropertyDefault("AUTOMOC_MOC_OPTIONS", 0); this->SetPropertyDefault("LINK_INTERFACE_LIBRARIES", 0); + this->SetPropertyDefault("WIN32_EXECUTABLE", 0); + this->SetPropertyDefault("MACOSX_BUNDLE", 0); // Collect the set of configuration types. std::vector<std::string> configNames; @@ -1263,6 +1283,11 @@ void cmTarget::SetMakefile(cmMakefile* mf) // Save the backtrace of target construction. this->Makefile->GetBacktrace(this->Internal->Backtrace); + // Initialize the INCLUDE_DIRECTORIES property based on the current value + // of the same directory property: + this->SetProperty("INCLUDE_DIRECTORIES", + this->Makefile->GetProperty("INCLUDE_DIRECTORIES")); + // Record current policies for later use. this->PolicyStatusCMP0003 = this->Makefile->GetPolicyStatus(cmPolicies::CMP0003); @@ -2582,54 +2607,6 @@ const char *cmTarget::GetProperty(const char* prop) } //---------------------------------------------------------------------------- -void cmTarget::ComputeObjectFiles() -{ - if (this->IsImported()) - { - return; - } -#if 0 - std::vector<std::string> dirs; - this->Makefile->GetLocalGenerator()-> - GetTargetObjectFileDirectories(this, - dirs); - std::string objectFiles; - std::string objExtensionLookup1 = "CMAKE_"; - std::string objExtensionLookup2 = "_OUTPUT_EXTENSION"; - - for(std::vector<std::string>::iterator d = dirs.begin(); - d != dirs.end(); ++d) - { - for(std::vector<cmSourceFile*>::iterator s = this->SourceFiles.begin(); - s != this->SourceFiles.end(); ++s) - { - cmSourceFile* sf = *s; - if(const char* lang = sf->GetLanguage()) - { - std::string lookupObj = objExtensionLookup1 + lang; - lookupObj += objExtensionLookup2; - const char* obj = this->Makefile->GetDefinition(lookupObj.c_str()); - if(obj) - { - if(objectFiles.size()) - { - objectFiles += ";"; - } - std::string objFile = *d; - objFile += "/"; - objFile += this->Makefile->GetLocalGenerator()-> - GetSourceObjectName(*sf); - objFile += obj; - objectFiles += objFile; - } - } - } - } - this->SetProperty("OBJECT_FILES", objectFiles.c_str()); -#endif -} - -//---------------------------------------------------------------------------- const char *cmTarget::GetProperty(const char* prop, cmProperty::ScopeType scope) { @@ -3586,7 +3563,8 @@ bool cmTarget::HaveBuildTreeRPATH() bool cmTarget::HaveInstallTreeRPATH() { const char* install_rpath = this->GetProperty("INSTALL_RPATH"); - return install_rpath && *install_rpath; + return (install_rpath && *install_rpath) && + !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH"); } //---------------------------------------------------------------------------- @@ -3693,7 +3671,8 @@ std::string cmTarget::GetInstallNameDirForInstallTree(const char* config, { std::string dir; - if(!this->Makefile->IsOn("CMAKE_SKIP_RPATH")) + if(!this->Makefile->IsOn("CMAKE_SKIP_RPATH") && + !this->Makefile->IsOn("CMAKE_SKIP_INSTALL_RPATH")) { const char* install_name_dir = this->GetProperty("INSTALL_NAME_DIR"); if(install_name_dir && *install_name_dir) @@ -4660,6 +4639,30 @@ cmTarget::GetLinkInformation(const char* config) } //---------------------------------------------------------------------------- +std::vector<std::string> cmTarget::GetIncludeDirectories() +{ + std::vector<std::string> includes; + const char *prop = this->GetProperty("INCLUDE_DIRECTORIES"); + if(prop) + { + cmSystemTools::ExpandListArgument(prop, includes); + } + + std::set<std::string> uniqueIncludes; + std::vector<std::string> orderedAndUniqueIncludes; + for(std::vector<std::string>::const_iterator + li = includes.begin(); li != includes.end(); ++li) + { + if(uniqueIncludes.insert(*li).second) + { + orderedAndUniqueIncludes.push_back(*li); + } + } + + return orderedAndUniqueIncludes; +} + +//---------------------------------------------------------------------------- cmTargetLinkInformationMap ::cmTargetLinkInformationMap(cmTargetLinkInformationMap const& r): derived() { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index f4b6955..ff05cd3 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -403,9 +403,6 @@ public: // Define the properties static void DefineProperties(cmake *cm); - // Compute the OBJECT_FILES property only when requested - void ComputeObjectFiles(); - /** Get the macro to define when building sources in this target. If no macro should be defined null is returned. */ const char* GetExportMacro(); @@ -457,6 +454,9 @@ public: directory. */ bool UsesDefaultOutputDir(const char* config, bool implib); + /** Get the include directories for this target. */ + std::vector<std::string> GetIncludeDirectories(); + private: /** * A list of direct dependencies. Use in conjunction with DependencyMap. diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 9418761..66f9a36 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -394,6 +394,11 @@ void cmVisualStudio10TargetGenerator::WriteProjectConfigurationValues() { this->WriteString("<CharacterSet>Unicode</CharacterSet>\n", 2); } + else if (this->Target->GetType() <= cmTarget::MODULE_LIBRARY && + this->ClOptions[*i]->UsingSBCS()) + { + this->WriteString("<CharacterSet>NotSet</CharacterSet>\n", 2); + } else { this->WriteString("<CharacterSet>MultiByte</CharacterSet>\n", 2); @@ -872,9 +877,6 @@ void cmVisualStudio10TargetGenerator::WriteCLSources() void cmVisualStudio10TargetGenerator::ComputeObjectNames() { - // We may be modifying the source groups temporarily, so make a copy. - std::vector<cmSourceGroup> sourceGroups = this->Makefile->GetSourceGroups(); - // get the classes from the source lists then add them to the groups std::vector<cmSourceFile*>const & classes = this->Target->GetSourceFiles(); for(std::vector<cmSourceFile*>::const_iterator i = classes.begin(); @@ -886,13 +888,10 @@ void cmVisualStudio10TargetGenerator::ComputeObjectNames() { this->ModuleDefinitionFile = (*i)->GetFullPath(); } - cmSourceGroup& sourceGroup = - this->Makefile->FindSourceGroup(source.c_str(), sourceGroups); - sourceGroup.AssignSource(*i); } // Compute which sources need unique object computation. - this->LocalGenerator->ComputeObjectNameRequirements(sourceGroups); + this->LocalGenerator->ComputeObjectNameRequirements(classes); } bool cmVisualStudio10TargetGenerator::OutputSourceSpecificFlags( @@ -1586,7 +1585,7 @@ void cmVisualStudio10TargetGenerator::WriteItemDefinitionGroups() static_cast<cmGlobalVisualStudio7Generator *> (this->GlobalGenerator)->GetConfigurations(); std::vector<std::string> includes; - this->LocalGenerator->GetIncludeDirectories(includes); + this->LocalGenerator->GetIncludeDirectories(includes, this->Target); for(std::vector<std::string>::iterator i = configs->begin(); i != configs->end(); ++i) { diff --git a/Source/cmVisualStudioGeneratorOptions.cxx b/Source/cmVisualStudioGeneratorOptions.cxx index 41230e7..9369af6 100644 --- a/Source/cmVisualStudioGeneratorOptions.cxx +++ b/Source/cmVisualStudioGeneratorOptions.cxx @@ -117,6 +117,20 @@ bool cmVisualStudioGeneratorOptions::UsingUnicode() } return false; } +//---------------------------------------------------------------------------- +bool cmVisualStudioGeneratorOptions::UsingSBCS() +{ + // Look for the a _SBCS definition. + for(std::vector<std::string>::const_iterator di = this->Defines.begin(); + di != this->Defines.end(); ++di) + { + if(*di == "_SBCS") + { + return true; + } + } + return false; +} //---------------------------------------------------------------------------- void cmVisualStudioGeneratorOptions::Parse(const char* flags) diff --git a/Source/cmVisualStudioGeneratorOptions.h b/Source/cmVisualStudioGeneratorOptions.h index 51a1362..a1a55da 100644 --- a/Source/cmVisualStudioGeneratorOptions.h +++ b/Source/cmVisualStudioGeneratorOptions.h @@ -48,6 +48,7 @@ public: // Check for specific options. bool UsingUnicode(); + bool UsingSBCS(); bool IsDebug(); // Write options to output. diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 0b7a996..846aef5 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -84,6 +84,10 @@ #endif #include "cmGlobalUnixMakefileGenerator3.h" +#ifdef CMAKE_USE_NINJA +# include "cmGlobalNinjaGenerator.h" +#endif + #if defined(CMAKE_HAVE_VS_GENERATORS) #include "cmCallVisualStudioMacro.h" #endif @@ -598,14 +602,10 @@ bool cmake::FindPackage(const std::vector<std::string>& args) std::string includes = mf->GetSafeDefinition("PACKAGE_INCLUDE_DIRS"); std::vector<std::string> includeDirs; cmSystemTools::ExpandListArgument(includes, includeDirs); - for(std::vector<std::string>::const_iterator dirIt=includeDirs.begin(); - dirIt != includeDirs.end(); - ++dirIt) - { - mf->AddIncludeDirectory(dirIt->c_str(), false); - } - std::string includeFlags = lg->GetIncludeFlags(language.c_str(), false); + std::string includeFlags = lg->GetIncludeFlags(includeDirs, + language.c_str(), false); + std::string definitions = mf->GetSafeDefinition("PACKAGE_DEFINITIONS"); printf("%s %s\n", includeFlags.c_str(), definitions.c_str()); } @@ -2597,6 +2597,10 @@ void cmake::AddDefaultGenerators() #endif this->Generators[cmGlobalUnixMakefileGenerator3::GetActualName()] = &cmGlobalUnixMakefileGenerator3::New; +#ifdef CMAKE_USE_NINJA + this->Generators[cmGlobalNinjaGenerator::GetActualName()] = + &cmGlobalNinjaGenerator::New; +#endif #ifdef CMAKE_USE_XCODE this->Generators[cmGlobalXCodeGenerator::GetActualName()] = &cmGlobalXCodeGenerator::New; diff --git a/Source/kwsys/kwsysDateStamp.cmake b/Source/kwsys/kwsysDateStamp.cmake index e424fec..6ee6e5b 100644 --- a/Source/kwsys/kwsysDateStamp.cmake +++ b/Source/kwsys/kwsysDateStamp.cmake @@ -18,4 +18,4 @@ SET(KWSYS_DATE_STAMP_YEAR 2012) SET(KWSYS_DATE_STAMP_MONTH 03) # KWSys version date day component. Format is DD. -SET(KWSYS_DATE_STAMP_DAY 03) +SET(KWSYS_DATE_STAMP_DAY 19) diff --git a/Tests/BuildDepends/CMakeLists.txt b/Tests/BuildDepends/CMakeLists.txt index 31392b5..aa32d67 100644 --- a/Tests/BuildDepends/CMakeLists.txt +++ b/Tests/BuildDepends/CMakeLists.txt @@ -40,6 +40,8 @@ if("${CMAKE_GENERATOR}" MATCHES "Make") endif() list(APPEND _cmake_options "-DTEST_LINK_DEPENDS=${TEST_LINK_DEPENDS}") +list(APPEND _cmake_options "-DCMAKE_FORCE_DEPFILES=1") + file(MAKE_DIRECTORY ${BuildDepends_BINARY_DIR}/Project) message("Creating Project/foo.cxx") write_file(${BuildDepends_BINARY_DIR}/Project/foo.cxx diff --git a/Tests/CMakeCommands/CMakeLists.txt b/Tests/CMakeCommands/CMakeLists.txt deleted file mode 100644 index aa400d0..0000000 --- a/Tests/CMakeCommands/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -macro(add_CMakeCommands_test test) - add_test(CMakeCommands.${test} ${CMAKE_CMAKE_COMMAND} - -DCMake_SOURCE_DIR=${CMake_SOURCE_DIR} # TODO: Remove - -Ddir=${CMAKE_CURRENT_BINARY_DIR}/${test} - -Dgen=${CMAKE_TEST_GENERATOR} - -P "${CMAKE_CURRENT_SOURCE_DIR}/${test}/test.cmake" - ) -endmacro() - -add_CMakeCommands_test(build_command) -add_CMakeCommands_test(find_package) diff --git a/Tests/CMakeCommands/build_command/test.cmake b/Tests/CMakeCommands/build_command/test.cmake deleted file mode 100644 index 55d9359..0000000 --- a/Tests/CMakeCommands/build_command/test.cmake +++ /dev/null @@ -1,86 +0,0 @@ -if(NOT DEFINED CMake_SOURCE_DIR) - message(FATAL_ERROR "CMake_SOURCE_DIR not defined") -endif() - -if(NOT DEFINED dir) - message(FATAL_ERROR "dir not defined") -endif() - -if(NOT DEFINED gen) - message(FATAL_ERROR "gen not defined") -endif() - -message(STATUS "CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") - -# Run cmake: -# -function(run_cmake build_dir extra_args expected_result expected_output expected_error) - message(STATUS "run_cmake build_dir='${build_dir}' extra_args='${extra_args}'") - - # Ensure build_dir exists: - # - execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${build_dir}) - - # Run cmake: - # - execute_process(COMMAND ${CMAKE_COMMAND} - ${extra_args} - -G ${gen} ${CMake_SOURCE_DIR}/Tests/CMakeCommands/build_command - RESULT_VARIABLE result - OUTPUT_VARIABLE stdout - ERROR_VARIABLE stderr - WORKING_DIRECTORY ${build_dir} - ) - - message(STATUS "result='${result}'") - message(STATUS "stdout='${stdout}'") - message(STATUS "stderr='${stderr}'") - message(STATUS "") - - # Verify result and output match expectations: - # - if("0" STREQUAL "${expected_result}") - if(NOT "${result}" STREQUAL "0") - message(FATAL_ERROR - "error: result='${result}' is non-zero and different than expected_result='${expected_result}'") - endif() - else() - if("${result}" STREQUAL "0") - message(FATAL_ERROR - "error: result='${result}' is zero and different than expected_result='${expected_result}'") - endif() - endif() - - foreach(e ${expected_output}) - if(NOT stdout MATCHES "${e}") - message(FATAL_ERROR - "error: stdout does not match expected_output item e='${e}'") - else() - message(STATUS "info: stdout matches '${e}'") - endif() - endforeach() - - foreach(e ${expected_error}) - if(NOT stderr MATCHES "${e}") - message(FATAL_ERROR - "error: stderr does not match expected_error item e='${e}'") - else() - message(STATUS "info: stderr matches '${e}'") - endif() - endforeach() - - message(STATUS "result, stdout and stderr match all expectations: test passes") - message(STATUS "") -endfunction() - - -# Expect this case to succeed: -run_cmake("${dir}/b1" "" 0 - "Build files have been written to:" - "skipping cases 1, 2 and 3 because TEST_ERROR_CONDITIONS is OFF") - - -# Expect this one to fail: -run_cmake("${dir}/b2" "-DTEST_ERROR_CONDITIONS:BOOL=ON" 1 - "Configuring incomplete, errors occurred!" - "build_command requires at least one argument naming a CMake variable;build_command unknown argument ") diff --git a/Tests/CMakeCommands/find_package/CMakeLists.txt b/Tests/CMakeCommands/find_package/CMakeLists.txt deleted file mode 100644 index c2deed0..0000000 --- a/Tests/CMakeCommands/find_package/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(${TEST} NONE) -include(${TEST}.cmake) diff --git a/Tests/CMakeCommands/find_package/MissingConfig.cmake b/Tests/CMakeCommands/find_package/MissingConfig.cmake deleted file mode 100644 index 3cebef1..0000000 --- a/Tests/CMakeCommands/find_package/MissingConfig.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere CONFIG) diff --git a/Tests/CMakeCommands/find_package/MissingConfigRequired.cmake b/Tests/CMakeCommands/find_package/MissingConfigRequired.cmake deleted file mode 100644 index 3c28552..0000000 --- a/Tests/CMakeCommands/find_package/MissingConfigRequired.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere CONFIG REQUIRED) diff --git a/Tests/CMakeCommands/find_package/MissingModule.cmake b/Tests/CMakeCommands/find_package/MissingModule.cmake deleted file mode 100644 index 420539f..0000000 --- a/Tests/CMakeCommands/find_package/MissingModule.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere MODULE) diff --git a/Tests/CMakeCommands/find_package/MissingModuleRequired.cmake b/Tests/CMakeCommands/find_package/MissingModuleRequired.cmake deleted file mode 100644 index 07f36c5..0000000 --- a/Tests/CMakeCommands/find_package/MissingModuleRequired.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere MODULE REQUIRED) diff --git a/Tests/CMakeCommands/find_package/MissingNormal.cmake b/Tests/CMakeCommands/find_package/MissingNormal.cmake deleted file mode 100644 index 778cd38..0000000 --- a/Tests/CMakeCommands/find_package/MissingNormal.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere) diff --git a/Tests/CMakeCommands/find_package/MissingNormalRequired.cmake b/Tests/CMakeCommands/find_package/MissingNormalRequired.cmake deleted file mode 100644 index 5c33fca..0000000 --- a/Tests/CMakeCommands/find_package/MissingNormalRequired.cmake +++ /dev/null @@ -1 +0,0 @@ -find_package(NotHere REQUIRED) diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 00cac94..5f125a4 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -53,7 +53,7 @@ IF(BUILD_TESTING) ADD_SUBDIRECTORY(CMakeLib) ADD_SUBDIRECTORY(CMakeOnly) - ADD_SUBDIRECTORY(CMakeCommands) + ADD_SUBDIRECTORY(RunCMake) ADD_SUBDIRECTORY(FindPackageModeMakefileTest) @@ -233,12 +233,35 @@ IF(BUILD_TESTING) LIST(APPEND TEST_BUILD_DIRS ${CMake_TEST_INSTALL_PREFIX}) + IF(NOT QT4_FOUND) + FIND_PACKAGE(Qt4) + ENDIF(NOT QT4_FOUND) + + IF(QT4_FOUND) + # test whether the Qt4 which has been found works, on some machines + # which run nightly builds there were errors like "wrong file format" + # for libQtCore.so. So first check it works, and only if it does add + # the automoc test. + INCLUDE(CheckCXXSourceCompiles) + SET(_save_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") + SET(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") + + SET(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES}) + SET(CMAKE_REQUIRED_LIBRARIES ${QT_QTCORE_LIBRARIES}) + + CHECK_CXX_SOURCE_COMPILES("#include <QCoreApplication>\n int main() {return (qApp == 0 ? 0 : 1); }\n" + QT4_WORKS) + + SET(CMAKE_REQUIRED_INCLUDES "${_save_CMAKE_REQUIRED_INCLUDES}") + SET(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}") + ENDIF() # run test for BundleUtilities on supported platforms/compilers if(MSVC OR CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "Darwin") if(NOT "${CMAKE_TEST_GENERATOR}" STREQUAL "Watcom WMake") + ADD_TEST(BundleUtilities ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/BundleUtilities" @@ -248,6 +271,24 @@ IF(BUILD_TESTING) --build-project BundleUtilities ) LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/BundleUtilities") + + # run test for DeployQt4 on supported platforms/compilers (which depends on BundleUtilities) + # this test also depends on the existence of the standard qtiff plugin + if(QT4_WORKS AND QT_QTSQL_FOUND) + ADD_TEST(Qt4Deploy ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Qt4Deploy" + "${CMake_BINARY_DIR}/Tests/Qt4Deploy" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-project Qt4Deploy + --build-options + -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} + -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Qt4Deploy") + endif() + endif() endif() @@ -366,6 +407,15 @@ IF(BUILD_TESTING) --build-target car --test-command car ) + + IF(${CMAKE_TEST_GENERATOR} MATCHES "Ninja") + # The Ninja generator does not create a recursive build system. Start + # from the root directory. + SET(SubProject_SUBDIR) + ELSE() + SET(SubProject_SUBDIR "/foo") + ENDIF() + # For stage 2, do not run cmake again. # Then build the foo sub project which should build # the bar library which should be referenced because @@ -373,13 +423,14 @@ IF(BUILD_TESTING) # directly in the foo sub project ADD_TEST(SubProject-Stage2 ${CMAKE_CTEST_COMMAND} --build-and-test - "${CMake_SOURCE_DIR}/Tests/SubProject/foo" - "${CMake_BINARY_DIR}/Tests/SubProject/foo" + "${CMake_SOURCE_DIR}/Tests/SubProject${SubProject_SUBDIR}" + "${CMake_BINARY_DIR}/Tests/SubProject${SubProject_SUBDIR}" --build-generator ${CMAKE_TEST_GENERATOR} --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} --build-nocmake --build-project foo --build-target foo + --build-exe-dir "${CMake_BINARY_DIR}/Tests/SubProject/foo" --test-command foo ) SET_TESTS_PROPERTIES ( SubProject-Stage2 PROPERTIES DEPENDS SubProject) @@ -861,43 +912,20 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ ) LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Environment") - IF(NOT QT4_FOUND) - FIND_PACKAGE(Qt4) - ENDIF(NOT QT4_FOUND) - - IF(QT4_FOUND) - # test whether the Qt4 which has been found works, on some machines - # which run nightly builds there were errors like "wrong file format" - # for libQtCore.so. So first check it works, and only if it does add - # the automoc test. - INCLUDE(CheckCXXSourceCompiles) - SET(_save_CMAKE_REQUIRED_INCLUDES "${CMAKE_REQUIRED_INCLUDES}") - SET(_save_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") - - SET(CMAKE_REQUIRED_INCLUDES ${QT_INCLUDES}) - SET(CMAKE_REQUIRED_LIBRARIES ${QT_QTCORE_LIBRARIES}) - - CHECK_CXX_SOURCE_COMPILES("#include <QCoreApplication>\n int main() {return (qApp == 0 ? 0 : 1); }\n" - QT4_WORKS_FOR_AUTOMOC_TEST) - - SET(CMAKE_REQUIRED_INCLUDES "${_save_CMAKE_REQUIRED_INCLUDES}") - SET(CMAKE_REQUIRED_LIBRARIES "${_save_CMAKE_REQUIRED_LIBRARIES}") - - IF(QT4_WORKS_FOR_AUTOMOC_TEST) - ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} - --build-and-test - "${CMake_SOURCE_DIR}/Tests/QtAutomoc" - "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --build-generator ${CMAKE_TEST_GENERATOR} - --build-project QtAutomoc - --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} - --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" - --force-new-ctest-process - --build-options -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} - --test-command ${CMAKE_CTEST_COMMAND} -V - ) - LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") - ENDIF() + IF(QT4_WORKS AND QT_QTGUI_FOUND) + ADD_TEST(QtAutomoc ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/QtAutomoc" + "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --build-generator ${CMAKE_TEST_GENERATOR} + --build-project QtAutomoc + --build-makeprogram ${CMAKE_TEST_MAKEPROGRAM} + --build-exe-dir "${CMake_BINARY_DIR}/Tests/QtAutomoc" + --force-new-ctest-process + --build-options -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} + --test-command ${CMAKE_CTEST_COMMAND} -V + ) + LIST(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/QtAutomoc") ENDIF() ADD_TEST(ExternalProject ${CMAKE_CTEST_COMMAND} @@ -1320,6 +1348,10 @@ ${CMake_BINARY_DIR}/bin/cmake -DVERSION=master -P ${CMake_SOURCE_DIR}/Utilities/ endif() IF(${CMAKE_TEST_GENERATOR} MATCHES "Visual Studio") + IF(NOT MSVC60) + ADD_TEST_MACRO(SBCS SBCS) + ENDIF(NOT MSVC60) + ADD_TEST(VSExternalInclude ${CMAKE_CTEST_COMMAND} --build-and-test "${CMake_SOURCE_DIR}/Tests/VSExternalInclude" diff --git a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt index e6e4c74..22b1b7b 100644 --- a/Tests/CMakeOnly/AllFindModules/CMakeLists.txt +++ b/Tests/CMakeOnly/AllFindModules/CMakeLists.txt @@ -61,7 +61,7 @@ endmacro(check_version_string) # reported. foreach(VTEST ALSA ARMADILLO BZIP2 CUPS CURL EXPAT FREETYPE GETTEXT GIT HSPELL - JASPER LIBXML2 LIBXSLT PERL PostgreSQL TCLSH TIFF ZLIB) + JASPER LIBXML2 LIBXSLT PERL PostgreSQL TIFF ZLIB) check_version_string(${VTEST} ${VTEST}_VERSION_STRING) endforeach(VTEST) diff --git a/Tests/CMakeTests/CMakeLists.txt b/Tests/CMakeTests/CMakeLists.txt index aa4d52e..c42c490 100644 --- a/Tests/CMakeTests/CMakeLists.txt +++ b/Tests/CMakeTests/CMakeLists.txt @@ -22,6 +22,7 @@ AddCMakeTest(ConfigureFile "") AddCMakeTest(SeparateArguments "") AddCMakeTest(ImplicitLinkInfo "") AddCMakeTest(ModuleNotices "") +AddCMakeTest(GetProperty "") AddCMakeTest(If "") AddCMakeTest(String "") AddCMakeTest(Math "") @@ -56,14 +57,13 @@ AddCMakeTest(GetPrerequisites "${GetPrerequisites_PreArgs}") # suite. It detects if any changes have been made to the CMake source tree # by any previous configure, build or test steps. # -if(do_cvs_tests OR GIT_EXECUTABLE) +if(GIT_EXECUTABLE) string(REPLACE "\\" "/" ENV_HOME "$ENV{HOME}") set(CheckSourceTree_PreArgs "-DCMake_BINARY_DIR:PATH=${CMake_BINARY_DIR}" "-DCMake_SOURCE_DIR:PATH=${CMake_SOURCE_DIR}" - "-DCVS_EXECUTABLE:STRING=${CVS_EXECUTABLE}" "-DGIT_EXECUTABLE:STRING=${GIT_EXECUTABLE}" "-DHOME:STRING=${ENV_HOME}" ) AddCMakeTest(CheckSourceTree "${CheckSourceTree_PreArgs}") -endif(do_cvs_tests OR GIT_EXECUTABLE) +endif() diff --git a/Tests/CMakeTests/CheckSourceTreeTest.cmake.in b/Tests/CMakeTests/CheckSourceTreeTest.cmake.in index 73f8b01..59b2890 100644 --- a/Tests/CMakeTests/CheckSourceTreeTest.cmake.in +++ b/Tests/CMakeTests/CheckSourceTreeTest.cmake.in @@ -5,7 +5,6 @@ message("CTEST_FULL_OUTPUT (Avoid ctest truncation of output)") message("") message("CMake_BINARY_DIR='${CMake_BINARY_DIR}'") message("CMake_SOURCE_DIR='${CMake_SOURCE_DIR}'") -message("CVS_EXECUTABLE='${CVS_EXECUTABLE}'") message("GIT_EXECUTABLE='${GIT_EXECUTABLE}'") message("HOME='${HOME}'") message("ENV{DASHBOARD_TEST_FROM_CTEST}='$ENV{DASHBOARD_TEST_FROM_CTEST}'") @@ -43,7 +42,7 @@ message("in_source_build='${in_source_build}'") message("") -# If this does not appear to be a git or CVS checkout, just pass the test here +# If this does not appear to be a git checkout, just pass the test here # and now. (Do not let the test fail if it is run in a tree *exported* from a # repository or unpacked from a .zip file source installer...) # @@ -52,29 +51,13 @@ if(EXISTS "${CMake_SOURCE_DIR}/.git") set(is_git_checkout 1) endif() -set(is_cvs_checkout 0) -if(EXISTS "${CMake_SOURCE_DIR}/CVS/Root") - set(is_cvs_checkout 1) -endif() - message("is_git_checkout='${is_git_checkout}'") -message("is_cvs_checkout='${is_cvs_checkout}'") message("") -if(NOT is_cvs_checkout) if(NOT is_git_checkout) - message("source tree is neither git nor CVS checkout... test passes by early return...") + message("source tree is not a git checkout... test passes by early return...") return() endif() -endif() - -if(is_cvs_checkout) -if(is_git_checkout) - message("warning: source tree has both git *and* CVS file system bits???") - # should this condition be a FATAL_ERROR test failure...? -endif() -endif() - # This test looks for the following types of changes in the source tree: # @@ -83,51 +66,13 @@ set(conflicts 0) set(modifications 0) set(nonadditions 0) -# ov == output variable... conditionally filled in by either cvs or git below: +# ov == output variable... conditionally filled in by either git below: # set(cmd "") set(ov "") set(ev "") set(rv "") - -if(is_cvs_checkout AND CVS_EXECUTABLE) - # Check with "cvs -q -n up -dP" if there are any local modifications to the - # CMake source tree: - # - message("=============================================================================") - message("This is a cvs checkout, using cvs to verify source tree....") - message("") - - execute_process(COMMAND ${CVS_EXECUTABLE} --version - WORKING_DIRECTORY ${CMake_SOURCE_DIR} - OUTPUT_VARIABLE version_output - OUTPUT_STRIP_TRAILING_WHITESPACE) - message("=== output of 'cvs --version' ===") - message("${version_output}") - message("=== end output ===") - message("") - - file(READ "${CMake_SOURCE_DIR}/CVS/Root" contents) - message("=== content of CVS/Root ===") - message("${contents}") - message("=== end content ===") - message("") - - file(READ "${CMake_SOURCE_DIR}/CVS/Repository" contents) - message("=== content of CVS/Repository ===") - message("${contents}") - message("=== end content ===") - message("") - - message("Copy/paste this command to reproduce:") - message("cd \"${CMake_SOURCE_DIR}\" && \"${CVS_EXECUTABLE}\" -q -n up -dP") - message("") - - set(cmd ${CVS_EXECUTABLE} -q -n up -dP) -endif() - - # If no GIT_EXECUTABLE, see if we can figure out which git was used # for the ctest_update step on this dashboard... # @@ -268,8 +213,8 @@ endif() if(cmd) - # Use the HOME value passed in to the script for calling cvs/git so it can - # find its .cvspass or user/global config settings... + # Use the HOME value passed in to the script for calling git so it can + # find its user/global config settings... # set(original_ENV_HOME "$ENV{HOME}") set(ENV{HOME} "${HOME}") @@ -322,28 +267,6 @@ if(NOT ov STREQUAL "") endif() if(consider) - if(is_cvs_checkout) - if(line MATCHES "^A ") - message(" locally added file/directory detected...") - set(additions 1) - endif() - - if(line MATCHES "^C ") - message(" conflict detected...") - set(conflicts 1) - endif() - - if(line MATCHES "^M ") - message(" locally modified file detected...") - set(modifications 1) - endif() - - if(line MATCHES "^\\? ") - message(" locally non-added file/directory detected...") - set(nonadditions 1) - endif() - endif() - if(is_git_checkout) if(line MATCHES "^#[ \t]*modified:") message(" locally modified file detected...") diff --git a/Tests/CMakeTests/GetProperty-Bad-Argument.cmake b/Tests/CMakeTests/GetProperty-Bad-Argument.cmake new file mode 100644 index 0000000..382dabb --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Bad-Argument.cmake @@ -0,0 +1 @@ +get_property(FOO GLOBAL PROPERTY FOO FOO) diff --git a/Tests/CMakeTests/GetProperty-Bad-Directory.cmake b/Tests/CMakeTests/GetProperty-Bad-Directory.cmake new file mode 100644 index 0000000..cdbfa80 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Bad-Directory.cmake @@ -0,0 +1 @@ +get_property(FOO DIRECTORY NonExistentSubDir PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-Bad-Scope.cmake b/Tests/CMakeTests/GetProperty-Bad-Scope.cmake new file mode 100644 index 0000000..ea8566b --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Bad-Scope.cmake @@ -0,0 +1 @@ +get_property(FOO FOO FOO) diff --git a/Tests/CMakeTests/GetProperty-Bad-Target.cmake b/Tests/CMakeTests/GetProperty-Bad-Target.cmake new file mode 100644 index 0000000..9992dab --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Bad-Target.cmake @@ -0,0 +1 @@ +get_property(FOO TARGET FOO PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-Bad-Test.cmake b/Tests/CMakeTests/GetProperty-Bad-Test.cmake new file mode 100644 index 0000000..44bf3eb --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Bad-Test.cmake @@ -0,0 +1 @@ +get_property(FOO TEST FOO PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-Doc-Properties.cmake b/Tests/CMakeTests/GetProperty-Doc-Properties.cmake new file mode 100644 index 0000000..6c2c362 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Doc-Properties.cmake @@ -0,0 +1,10 @@ +get_property(FOO_BRIEF GLOBAL PROPERTY FOO BRIEF_DOCS) +get_property(FOO_FULL GLOBAL PROPERTY FOO FULL_DOCS) + +if (NOT FOO_BRIEF STREQUAL "NOTFOUND") + message(SEND_ERROR "property FOO has BRIEF_DOCS set to '${FOO_BRIEF}'") +endif () + +if (NOT FOO_FULL STREQUAL "NOTFOUND") + message(SEND_ERROR "property FOO has FULL_DOCS set to '${FOO_FULL}'") +endif () diff --git a/Tests/CMakeTests/GetProperty-Global-Name.cmake b/Tests/CMakeTests/GetProperty-Global-Name.cmake new file mode 100644 index 0000000..497700c --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Global-Name.cmake @@ -0,0 +1 @@ +get_property(FOO GLOBAL FOO PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-Missing-Argument.cmake b/Tests/CMakeTests/GetProperty-Missing-Argument.cmake new file mode 100644 index 0000000..f0d004d --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Missing-Argument.cmake @@ -0,0 +1 @@ +get_property() diff --git a/Tests/CMakeTests/GetProperty-No-Cache.cmake b/Tests/CMakeTests/GetProperty-No-Cache.cmake new file mode 100644 index 0000000..9719fe7 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-No-Cache.cmake @@ -0,0 +1 @@ +get_property(FOO CACHE PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-No-Property.cmake b/Tests/CMakeTests/GetProperty-No-Property.cmake new file mode 100644 index 0000000..bee230d --- /dev/null +++ b/Tests/CMakeTests/GetProperty-No-Property.cmake @@ -0,0 +1 @@ +get_property(FOO GLOBAL PROPERTY) diff --git a/Tests/CMakeTests/GetProperty-No-Source.cmake b/Tests/CMakeTests/GetProperty-No-Source.cmake new file mode 100644 index 0000000..89773c8 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-No-Source.cmake @@ -0,0 +1 @@ +get_property(FOO SOURCE PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-No-Target.cmake b/Tests/CMakeTests/GetProperty-No-Target.cmake new file mode 100644 index 0000000..8f1fa23 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-No-Target.cmake @@ -0,0 +1 @@ +get_property(FOO TARGET PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-No-Test.cmake b/Tests/CMakeTests/GetProperty-No-Test.cmake new file mode 100644 index 0000000..045bd56 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-No-Test.cmake @@ -0,0 +1 @@ +get_property(FOO TEST PROPERTY FOO) diff --git a/Tests/CMakeTests/GetProperty-Variable-Name.cmake b/Tests/CMakeTests/GetProperty-Variable-Name.cmake new file mode 100644 index 0000000..9190f80 --- /dev/null +++ b/Tests/CMakeTests/GetProperty-Variable-Name.cmake @@ -0,0 +1 @@ +get_property(FOO VARIABLE FOO PROPERTY FOO) diff --git a/Tests/CMakeTests/GetPropertyTest.cmake.in b/Tests/CMakeTests/GetPropertyTest.cmake.in new file mode 100644 index 0000000..ab96e5b --- /dev/null +++ b/Tests/CMakeTests/GetPropertyTest.cmake.in @@ -0,0 +1,98 @@ +include("@CMAKE_CURRENT_SOURCE_DIR@/CheckCMakeTest.cmake") + +set(Missing-Argument-RESULT 1) +set(Missing-Argument-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Missing-Argument.cmake:1 \\(get_property\\):.*get_property called with incorrect number of arguments.*") + +check_cmake_test(GetProperty + Missing-Argument +) + +set(Bad-Scope-RESULT 1) +set(Bad-Scope-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Bad-Scope.cmake:1 \\(get_property\\):.*get_property given invalid scope FOO\\..*") + +check_cmake_test(GetProperty + Bad-Scope +) + +set(Bad-Argument-RESULT 1) +set(Bad-Argument-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Bad-Argument.cmake:1 \\(get_property\\):.*get_property given invalid argument \"FOO\"\\..*") + +check_cmake_test(GetProperty + Bad-Argument +) + +set(No-Property-RESULT 1) +set(No-Property-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-No-Property.cmake:1 \\(get_property\\):.*get_property not given a PROPERTY <name> argument\\..*") + +check_cmake_test(GetProperty + No-Property +) + +set(Doc-Properties-RESULT 0) + +check_cmake_test(GetProperty + Doc-Properties +) + +set(Global-Name-RESULT 1) +set(Global-Name-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Global-Name.cmake:1 \\(get_property\\):.*get_property given name for GLOBAL scope\\..*") + +check_cmake_test(GetProperty + Global-Name +) + +set(Bad-Directory-RESULT 1) +set(Bad-Directory-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Bad-Directory.cmake:1 \\(get_property\\):.*get_property DIRECTORY scope provided but requested directory was not.*found\\..*") + +check_cmake_test(GetProperty + Bad-Directory +) + +set(No-Target-RESULT 1) +set(No-Target-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-No-Target.cmake:1 \\(get_property\\):.*get_property not given name for TARGET scope\\..*") + +check_cmake_test(GetProperty + No-Target +) + +set(Bad-Target-RESULT 1) +set(Bad-Target-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Bad-Target.cmake:1 \\(get_property\\):.*get_property could not find TARGET FOO\\..*") + +check_cmake_test(GetProperty + Bad-Target +) + +set(No-Source-RESULT 1) +set(No-Source-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-No-Source.cmake:1 \\(get_property\\):.*get_property not given name for SOURCE scope\\..*") + +check_cmake_test(GetProperty + No-Source +) + +set(No-Test-RESULT 1) +set(No-Test-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-No-Test.cmake:1 \\(get_property\\):.*get_property not given name for TEST scope\\..*") + +check_cmake_test(GetProperty + No-Test +) + +set(Bad-Test-RESULT 1) +set(Bad-Test-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Bad-Test.cmake:1 \\(get_property\\):.*get_property given TEST name that does not exist: FOO.*") + +check_cmake_test(GetProperty + Bad-Test +) + +set(Variable-Name-RESULT 1) +set(Variable-Name-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-Variable-Name.cmake:1 \\(get_property\\):.*get_property given name for VARIABLE scope\\..*") + +check_cmake_test(GetProperty + Variable-Name +) + +set(No-Cache-RESULT 1) +set(No-Cache-STDERR ".*CMake Error at (@CMAKE_CURRENT_SOURCE_DIR@/)?GetProperty-No-Cache.cmake:1 \\(get_property\\):.*get_property not given name for CACHE scope\\..*") + +check_cmake_test(GetProperty + No-Cache +) diff --git a/Tests/CTestUpdateCVS.cmake.in b/Tests/CTestUpdateCVS.cmake.in index a04673e..f7f5db6 100644 --- a/Tests/CTestUpdateCVS.cmake.in +++ b/Tests/CTestUpdateCVS.cmake.in @@ -18,6 +18,19 @@ set(CVS "@CVS_EXECUTABLE@") message(" cvs = ${CVS}") set(REPO ${TOP}/repo) + +# The MSYS cvs tool interprets "c:/" as a "machine:" name for SSH. +# Detect the MSYS cvs and convert the repo path to an MSYS path. +if(WIN32) + if(EXISTS "${CVS}") + file(STRINGS "${CVS}" cvs_is_msys LIMIT_COUNT 1 REGEX "[Mm][Ss][Yy][Ss]") + if(cvs_is_msys) + message(" '${CVS}' is from MSYS (contains '${cvs_is_msys}')") + string(REGEX REPLACE "^([A-Za-z]):" "/\\1" REPO "${REPO}") + endif() + endif() +endif() + set(CVSCMD ${CVS} -d${REPO}) # CVSNT requires an extra option to 'cvs init'. diff --git a/Tests/CTestUpdateHG.cmake.in b/Tests/CTestUpdateHG.cmake.in index 543ddd9..5a9daae 100644 --- a/Tests/CTestUpdateHG.cmake.in +++ b/Tests/CTestUpdateHG.cmake.in @@ -28,7 +28,7 @@ run_child( WORKING_DIRECTORY ${TOP}/repo.hg COMMAND ${HG} init ) -set(REPO file://${TOP}/repo.hg) +set(REPO file:///${TOP}/repo.hg) #----------------------------------------------------------------------------- # Import initial content into the repository. diff --git a/Tests/ExternalProject/CMakeLists.txt b/Tests/ExternalProject/CMakeLists.txt index ac70129..7a76261 100644 --- a/Tests/ExternalProject/CMakeLists.txt +++ b/Tests/ExternalProject/CMakeLists.txt @@ -280,6 +280,18 @@ if(do_cvs_tests) set_property(TARGET ${proj} PROPERTY FOLDER "SetupRepos/Local/Deeply/Nested/For/Testing") + # The MSYS cvs tool interprets "c:/" as a "machine:" name for SSH. + # Detect the MSYS cvs and convert the repo path to an MSYS path. + if(WIN32) + if(EXISTS "${CVS_EXECUTABLE}") + file(STRINGS "${CVS_EXECUTABLE}" cvs_is_msys LIMIT_COUNT 1 REGEX "[Mm][Ss][Yy][Ss]") + if(cvs_is_msys) + message(STATUS "'${CVS_EXECUTABLE}' is from MSYS (contains '${cvs_is_msys}')") + string(REGEX REPLACE "^([A-Za-z]):" "/\\1" local_cvs_repo "${local_cvs_repo}") + endif() + endif() + endif() + # CVS by date stamp: # set(proj TutorialStep1-CVS-20090626) diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index 9a4bdfe..73f24e0 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -305,13 +305,39 @@ STRING(REGEX REPLACE "-.*$" "" version ${CMAKE_VERSION}) FIND_PACKAGE(CMakeTestExportPackage 1.${version} EXACT REQUIRED) #----------------------------------------------------------------------------- -# Test write_basic_config_version_file(). +# Test configure_package_config_file(). -include(WriteBasicConfigVersionFile) +include(CMakePackageConfigHelpers) -write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/Foo123ConfigVersion.cmake - VERSION 1.2.3 - COMPATIBILITY AnyNewerVersion) +set(INCLUDE_INSTALL_DIR include ) +set(SHARE_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/share/" ) +set(CURRENT_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}" ) + +configure_package_config_file(RelocatableConfig.cmake.in "${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake" + INSTALL_DESTINATION "${CMAKE_INSTALL_PREFIX}" + PATH_VARS INCLUDE_INSTALL_DIR SHARE_INSTALL_DIR CURRENT_BUILD_DIR + ) + +include("${CMAKE_CURRENT_BINARY_DIR}/RelocatableConfig.cmake") + +if(NOT "${RELOC_INCLUDE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/include") + message(SEND_ERROR "RELOC_INCLUDE_DIR set by configure_package_config_file() is set to \"${RELOC_INCLUDE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/include\")") +endif() + +if(NOT "${RELOC_SHARE_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}/share/") + message(SEND_ERROR "RELOC_SHARE_DIR set by configure_package_config_file() is set to \"${RELOC_SHARE_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}/share/\")") +endif() + +if(NOT "${RELOC_BUILD_DIR}" STREQUAL "${CMAKE_CURRENT_BINARY_DIR}") + message(SEND_ERROR "RELOC_BUILD_DIR set by configure_package_config_file() is set to \"${RELOC_BUILD_DIR}\" (expected \"${CMAKE_CURRENT_BINARY_DIR}\")") +endif() + +#----------------------------------------------------------------------------- +# Test write_basic_config_version_file(). + +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/Foo123ConfigVersion.cmake + VERSION 1.2.3 + COMPATIBILITY AnyNewerVersion) set(PACKAGE_FIND_VERSION 2.3.4) include(${CMAKE_CURRENT_BINARY_DIR}/Foo123ConfigVersion.cmake) @@ -345,6 +371,7 @@ endif() ####################### +include(WriteBasicConfigVersionFile) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/Boo123ConfigVersion.cmake VERSION 1.2.3 @@ -394,3 +421,73 @@ endif() if(PACKAGE_VERSION_UNSUITABLE) message(SEND_ERROR "PACKAGE_VERSION_UNSUITABLE set, but must not be !") endif() + +####################### + +write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake + VERSION 1.2.3.17 + COMPATIBILITY ExactVersion) + +set(PACKAGE_VERSION_EXACT FALSE) +set(PACKAGE_FIND_VERSION 2.3.4) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Found Bar123 with version 1.2.3 (2.3.4 was requested) !") +endif() +if(PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT set, although it should not be !") +endif() + +set(PACKAGE_FIND_VERSION 1.2) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Found Bar123 with version 1.2.3 (1.2 was requested) !") +endif() +if(PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT set, although it should not be !") +endif() + +set(PACKAGE_FIND_VERSION 1) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Found Bar123 with version 1.2.3 (1 was requested) !") +endif() +if(PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT set, although it should not be !") +endif() + +set(PACKAGE_FIND_VERSION 1.2.3.4) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(NOT PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Did not find Bar123 with version 1.2.3 (1.2.3.4 was requested) !") +endif() +if(PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT set, although it should not be !") +endif() + +set(PACKAGE_FIND_VERSION 1.2.3) +set(PACKAGE_VERSION_EXACT FALSE) +set(PACKAGE_VERSION_COMPATIBLE FALSE) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(NOT PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Did not find Bar123 with version 1.2.3 (1.2.3 was requested) !") +endif() +if(PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT set, although it should not be !") +endif() + + +set(PACKAGE_FIND_VERSION 1.2.3.17) +set(PACKAGE_VERSION_EXACT FALSE) +set(PACKAGE_VERSION_COMPATIBLE FALSE) +include(${CMAKE_CURRENT_BINARY_DIR}/Bar123ConfigVersion.cmake) +if(NOT PACKAGE_VERSION_COMPATIBLE) + message(SEND_ERROR "Did not find Bar123 with version 1.2.3 (1.2.3.17 was requested) !") +endif() +if(NOT PACKAGE_VERSION_EXACT) + message(SEND_ERROR "PACKAGE_VERSION_EXACT not set, although it should be !") +endif() + +if(PACKAGE_VERSION_UNSUITABLE) + message(SEND_ERROR "PACKAGE_VERSION_UNSUITABLE set, but must not be !") +endif() diff --git a/Tests/FindPackageTest/RelocatableConfig.cmake.in b/Tests/FindPackageTest/RelocatableConfig.cmake.in new file mode 100644 index 0000000..7a34b2f --- /dev/null +++ b/Tests/FindPackageTest/RelocatableConfig.cmake.in @@ -0,0 +1,5 @@ +@PACKAGE_INIT@ + +set(RELOC_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set(RELOC_SHARE_DIR "@PACKAGE_SHARE_INSTALL_DIR@") +set_and_check(RELOC_BUILD_DIR "@PACKAGE_CURRENT_BUILD_DIR@") diff --git a/Tests/IncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/CMakeLists.txt index 60b8c22..60f5e5e 100644 --- a/Tests/IncludeDirectories/CMakeLists.txt +++ b/Tests/IncludeDirectories/CMakeLists.txt @@ -45,3 +45,5 @@ else() set_target_properties(IncludeDirectories PROPERTIES COMPILE_FLAGS "-ITarProp") endif() + +add_subdirectory(TargetIncludeDirectories) diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt new file mode 100644 index 0000000..2cf36f5 --- /dev/null +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/CMakeLists.txt @@ -0,0 +1,26 @@ + +cmake_minimum_required(VERSION 2.8) + +project(TargetIncludeDirectories) + +macro(create_header _name) + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${_name}") + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${_name}/${_name}.h" + "//${_name}.h + ") +endmacro() + +create_header(bar) +create_header(bat) +create_header(foo) +create_header(baz) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +include_directories("${CMAKE_CURRENT_BINARY_DIR}/bar") + +add_executable(TargetIncludeDirectories main.cpp) +set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/bat") +set_property(TARGET TargetIncludeDirectories APPEND PROPERTY INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/foo") + +include_directories("${CMAKE_CURRENT_BINARY_DIR}/baz") diff --git a/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp new file mode 100644 index 0000000..8aa3532 --- /dev/null +++ b/Tests/IncludeDirectories/TargetIncludeDirectories/main.cpp @@ -0,0 +1,10 @@ + +#include "bar.h" +#include "bat.h" +#include "foo.h" +#include "baz.h" + +int main(int, char**) +{ + return 0; +} diff --git a/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt index c7cc090..c362e79 100644 --- a/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt +++ b/Tests/OutOfSource/OutOfSourceSubdir/CMakeLists.txt @@ -24,6 +24,12 @@ IF ("${PROJECT_SOURCE_DIR}" STREQUAL "${ANOTHER_PROJ_SOURCE_DIR}") MATH(EXPR MAXPATH "${MAXPATH} - 46") ENDIF() + # Ninja imposes a maximum path component count of 30. Permit more + # path components in the source path. + IF(${CMAKE_GENERATOR} MATCHES "Ninja") + MATH(EXPR MAXPATH "${MAXPATH} - 44") + ENDIF() + # MAXPATH less 25 for last /and/deeper/simple.cxx part and small safety MATH(EXPR MAXPATH "${MAXPATH} - 25") STRING(LENGTH "${DEEPDIR}" DEEPDIR_LEN) diff --git a/Tests/PrecompiledHeader/CMakeLists.txt b/Tests/PrecompiledHeader/CMakeLists.txt index d423cae..3374e32 100644 --- a/Tests/PrecompiledHeader/CMakeLists.txt +++ b/Tests/PrecompiledHeader/CMakeLists.txt @@ -47,7 +47,8 @@ SET_SOURCE_FILES_PROPERTIES(foo_precompile.c PROPERTIES # Setup dependencies for precompiled header creation and use. The VS # IDE takes care of this automatically. -IF("${CMAKE_GENERATOR}" MATCHES "Makefile") +IF("${CMAKE_GENERATOR}" MATCHES "Makefile" OR + "${CMAKE_GENERATOR}" MATCHES "Ninja") # This source file creates the precompiled header as a side-effect. SET_SOURCE_FILES_PROPERTIES(foo_precompile.c PROPERTIES OBJECT_OUTPUTS "${PCH_DIR}/foo_precompiled.pch") diff --git a/Tests/Qt4Deploy/CMakeLists.txt b/Tests/Qt4Deploy/CMakeLists.txt new file mode 100644 index 0000000..646ea9f --- /dev/null +++ b/Tests/Qt4Deploy/CMakeLists.txt @@ -0,0 +1,70 @@ +cmake_minimum_required(VERSION 2.8) + +project(Qt4Deploy) +set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_BINARY_DIR}/install) + +find_package(Qt4 REQUIRED QtMain QtCore QtSql) +include(${QT_USE_FILE}) + +add_executable(testdeploy MACOSX_BUNDLE testdeploy.cpp) +target_link_libraries(testdeploy ${QT_LIBRARIES}) +set_target_properties(testdeploy PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}") + +if(CMAKE_CONFIGURATION_TYPES AND QT_QTCORE_LIBRARY_RELEASE AND QT_QTCORE_LIBRARY_DEBUG) + # note: installing debug Qt libraries from a Qt installation configured with + # -debug-and-release not yet supported (very low priority). + install(CODE " + if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\") + return() + endif() + ") +endif() + +# install the Qt4 app with qsqlite plugin +install(CODE "file(REMOVE_RECURSE \"${CMAKE_INSTALL_PREFIX}\")") +install(TARGETS testdeploy DESTINATION .) +include(../../Modules/DeployQt4.cmake) +if(APPLE) + install_qt4_executable(testdeploy.app "qsqlite") +elseif(WIN32) + install_qt4_executable(testdeploy.exe "qsqlite") +else() + install_qt4_executable(testdeploy "qsqlite") +endif() + + +# test depends on standard qsqlite plugin +if(QT_QSQLITE_PLUGIN_DEBUG OR QT_QSQLITE_PLUGIN_RELEASE) + + # test the deployed Qt application + if(APPLE) + install(CODE " + message(STATUS \"executing: ${CMAKE_INSTALL_PREFIX}/testdeploy.app/Contents/MacOS/testdeploy\") + execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/testdeploy.app/Contents/MacOS/testdeploy\" + RESULT_VARIABLE result) + if(NOT result STREQUAL \"0\") + message(FATAL_ERROR \"error running testdeploy app\") + endif() + ") + else() + install(CODE " + message(STATUS \"executing: ${CMAKE_INSTALL_PREFIX}/testdeploy\") + execute_process(COMMAND \"${CMAKE_INSTALL_PREFIX}/testdeploy\" + RESULT_VARIABLE result) + if(NOT result STREQUAL \"0\") + message(FATAL_ERROR \"error running testdeploy app\") + endif() + ") + endif() + + # custom target to install and test the installation at build time + if(CMAKE_CONFIGURATION_TYPES) + set(install_config "-DCMAKE_INSTALL_CONFIG_NAME=${CMAKE_CFG_INTDIR}") + endif() + + add_custom_target(testdeploy_test ALL + COMMAND ${CMAKE_COMMAND} ${install_config} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake + COMMENT "${CMAKE_COMMAND} ${install_config} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_install.cmake" + DEPENDS testdeploy) + +endif() diff --git a/Tests/Qt4Deploy/testdeploy.cpp b/Tests/Qt4Deploy/testdeploy.cpp new file mode 100644 index 0000000..8b9c8d6 --- /dev/null +++ b/Tests/Qt4Deploy/testdeploy.cpp @@ -0,0 +1,29 @@ +#include <QCoreApplication> +#include <QSqlDatabase> +#include <QLibraryInfo> +#include <QDebug> +#include <QStringList> + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + + qDebug() << "App path:" << app.applicationDirPath(); + qDebug() << "Plugin path:" << QLibraryInfo::location(QLibraryInfo::PluginsPath); + + bool foundSqlite = false; + + qDebug() << "Supported Database Drivers:"; + foreach(const QString &sqlDriver, QSqlDatabase::drivers()) + { + qDebug() << " " << sqlDriver; + if(sqlDriver == "QSQLITE") + foundSqlite = true; + } + + if(foundSqlite) + qDebug() << "Found sqlite support from plugin."; + else + qDebug() << "Could not find sqlite support from plugin."; + return foundSqlite ? 0 : 1; +} diff --git a/Tests/README b/Tests/README index 9b0f5c1..8b2fda8 100644 --- a/Tests/README +++ b/Tests/README @@ -16,10 +16,15 @@ your test to the test runs. This includes tests that will build something using try_compile() and friends, but nothing that expects add_executable(), add_library(), or add_test() to run. -If this matches your test you should put it into the Tests/CMakeOnly/ directory. -Create a subdirectory named like your test and write the CMakeLists.txt you -need into that subdirectory. Use the add_CMakeOnly_test() macro from -Tests/CMakeOnly/CMakeLists.txt to add your test to the test runs. +If the test configures the project only once and it must succeed then put it +into the Tests/CMakeOnly/ directory. Create a subdirectory named like your +test and write the CMakeLists.txt you need into that subdirectory. Use the +add_CMakeOnly_test() macro from Tests/CMakeOnly/CMakeLists.txt to add your +test to the test runs. + +If the test configures the project with multiple variations and verifies +success or failure each time then put it into the Tests/RunCMake/ directory. +Read the instructions in Tests/RunCMake/CMakeLists.txt to add a test. 3. If you are testing something from the Modules directory diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt new file mode 100644 index 0000000..63fc9f8 --- /dev/null +++ b/Tests/RunCMake/CMakeLists.txt @@ -0,0 +1,44 @@ +# This directory contains tests that run CMake to configure a project +# but do not actually build anything. To add a test: +# +# 1.) Add a subdirectory named for the test. +# +# 2.) Call add_RunCMake_test and pass the test directory name. +# +# 3.) Create a RunCMakeTest.cmake script in the directory containing +# include(RunCMake) +# run_cmake(SubTest1) +# ... +# run_cmake(SubTestN) +# where SubTest1..SubTestN are sub-test names each corresponding to +# an independent CMake run and project configuration. +# +# 3.) Create a CMakeLists.txt file in the directory containing +# cmake_minimum_required(...) +# project(${RunCMake_TEST} NONE) # or languages needed +# include(${RunCMake_TEST}.cmake) +# where "${RunCMake_TEST}" is literal. A value for RunCMake_TEST +# will be passed to CMake by the run_cmake macro when running each +# sub-test. +# +# 4.) Create a <SubTest>.cmake file for each sub-test named above +# containing the actual test code. Optionally create files +# containing expected test results: +# <SubTest>-result.txt = Process result expected if not "0" +# <SubTest>-stdout.txt = Regex matching expected stdout content +# <SubTest>-stderr.txt = Regex matching expected stderr content +# Note that trailing newlines will be stripped from actual test +# output before matching against the stdout and stderr expressions. + +macro(add_RunCMake_test test) + add_test(RunCMake.${test} ${CMAKE_CMAKE_COMMAND} + -DCMAKE_MODULE_PATH=${CMAKE_CURRENT_SOURCE_DIR} + -DRunCMake_GENERATOR=${CMAKE_TEST_GENERATOR} + -DRunCMake_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/${test} + -DRunCMake_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/${test} + -P "${CMAKE_CURRENT_SOURCE_DIR}/${test}/RunCMakeTest.cmake" + ) +endmacro() + +add_RunCMake_test(build_command) +add_RunCMake_test(find_package) diff --git a/Tests/CMakeCommands/find_package/test.cmake b/Tests/RunCMake/RunCMake.cmake index dd1072e..2639463 100644 --- a/Tests/CMakeCommands/find_package/test.cmake +++ b/Tests/RunCMake/RunCMake.cmake @@ -1,15 +1,16 @@ -if(NOT DEFINED dir) - message(FATAL_ERROR "dir not defined") -endif() - -if(NOT DEFINED gen) - message(FATAL_ERROR "gen not defined") -endif() +foreach(arg + RunCMake_GENERATOR + RunCMake_SOURCE_DIR + RunCMake_BINARY_DIR + ) + if(NOT DEFINED ${arg}) + message(FATAL_ERROR "${arg} not given!") + endif() +endforeach() -# TODO: Generalize this for other tests. -function(run_test test) - set(top_src "${CMAKE_CURRENT_LIST_DIR}") - set(top_bin "${dir}") +function(run_cmake test) + set(top_src "${RunCMake_SOURCE_DIR}") + set(top_bin "${RunCMake_BINARY_DIR}") if(EXISTS ${top_src}/${test}-result.txt) file(READ ${top_src}/${test}-result.txt expect_result) string(REGEX REPLACE "\n+$" "" expect_result "${expect_result}") @@ -29,7 +30,8 @@ function(run_test test) file(REMOVE_RECURSE "${binary_dir}") file(MAKE_DIRECTORY "${binary_dir}") execute_process( - COMMAND ${CMAKE_COMMAND} "${source_dir}" -G "${gen}" -DTEST=${test} + COMMAND ${CMAKE_COMMAND} "${source_dir}" + -G "${RunCMake_GENERATOR}" -DRunCMake_TEST=${test} WORKING_DIRECTORY "${binary_dir}" OUTPUT_VARIABLE actual_stdout ERROR_VARIABLE actual_stderr @@ -65,16 +67,3 @@ function(run_test test) message(STATUS "${test} - PASSED") endif() endfunction() - -run_test(MissingNormal) -run_test(MissingNormalRequired) -run_test(MissingNormalVersion) -run_test(MissingNormalWarnNoModuleOld) -run_test(MissingNormalWarnNoModuleNew) -run_test(MissingModule) -run_test(MissingModuleRequired) -run_test(MissingConfig) -run_test(MissingConfigOneName) -run_test(MissingConfigRequired) -run_test(MissingConfigVersion) -run_test(MixedModeOptions) diff --git a/Tests/CMakeCommands/build_command/CMakeLists.txt b/Tests/RunCMake/build_command/CMakeLists.txt index 990ac90..0fbb948 100644 --- a/Tests/CMakeCommands/build_command/CMakeLists.txt +++ b/Tests/RunCMake/build_command/CMakeLists.txt @@ -1,3 +1,7 @@ +cmake_minimum_required(VERSION 2.8) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) + # This CMakeLists file is *sometimes expected* to result in a configure error. # # expect this to succeed: @@ -12,12 +16,9 @@ # ...even purposefully calling it with known-bad argument lists to cover # error handling code. # -cmake_minimum_required(VERSION 2.8) -project(test_build_command) set(cmd "initial") -message("CTEST_FULL_OUTPUT") message("0. begin") if(TEST_ERROR_CONDITIONS) diff --git a/Tests/RunCMake/build_command/ErrorsOFF-stderr.txt b/Tests/RunCMake/build_command/ErrorsOFF-stderr.txt new file mode 100644 index 0000000..331885b --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsOFF-stderr.txt @@ -0,0 +1 @@ +skipping cases 1, 2 and 3 because TEST_ERROR_CONDITIONS is OFF diff --git a/Tests/RunCMake/build_command/ErrorsOFF-stdout.txt b/Tests/RunCMake/build_command/ErrorsOFF-stdout.txt new file mode 100644 index 0000000..cf66a9d --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsOFF-stdout.txt @@ -0,0 +1 @@ +Build files have been written to: diff --git a/Tests/RunCMake/build_command/ErrorsOFF.cmake b/Tests/RunCMake/build_command/ErrorsOFF.cmake new file mode 100644 index 0000000..a243fab --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsOFF.cmake @@ -0,0 +1 @@ +set(TEST_ERROR_CONDITIONS OFF) diff --git a/Tests/CMakeCommands/find_package/MixedModeOptions-result.txt b/Tests/RunCMake/build_command/ErrorsON-result.txt index d00491f..d00491f 100644 --- a/Tests/CMakeCommands/find_package/MixedModeOptions-result.txt +++ b/Tests/RunCMake/build_command/ErrorsON-result.txt diff --git a/Tests/RunCMake/build_command/ErrorsON-stderr.txt b/Tests/RunCMake/build_command/ErrorsON-stderr.txt new file mode 100644 index 0000000..0be7475 --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsON-stderr.txt @@ -0,0 +1,12 @@ +CMake Error at CMakeLists.txt:[0-9]+ \(build_command\): + build_command requires at least one argument naming a CMake variable + ++ +1. cmd='initial' +CMake Error at CMakeLists.txt:[0-9]+ \(build_command\): + build_command unknown argument "BOGUS" + ++ +2. cmd='initial' +CMake Error at CMakeLists.txt:[0-9]+ \(build_command\): + build_command unknown argument "STUFF" diff --git a/Tests/RunCMake/build_command/ErrorsON-stdout.txt b/Tests/RunCMake/build_command/ErrorsON-stdout.txt new file mode 100644 index 0000000..841dd0d --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsON-stdout.txt @@ -0,0 +1 @@ +Configuring incomplete, errors occurred! diff --git a/Tests/RunCMake/build_command/ErrorsON.cmake b/Tests/RunCMake/build_command/ErrorsON.cmake new file mode 100644 index 0000000..27814bf --- /dev/null +++ b/Tests/RunCMake/build_command/ErrorsON.cmake @@ -0,0 +1 @@ +set(TEST_ERROR_CONDITIONS ON) diff --git a/Tests/RunCMake/build_command/RunCMakeTest.cmake b/Tests/RunCMake/build_command/RunCMakeTest.cmake new file mode 100644 index 0000000..4525c57 --- /dev/null +++ b/Tests/RunCMake/build_command/RunCMakeTest.cmake @@ -0,0 +1,4 @@ +include(RunCMake) + +run_cmake(ErrorsOFF) +run_cmake(ErrorsON) diff --git a/Tests/RunCMake/find_package/CMakeLists.txt b/Tests/RunCMake/find_package/CMakeLists.txt new file mode 100644 index 0000000..e8db6b0 --- /dev/null +++ b/Tests/RunCMake/find_package/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/CMakeCommands/find_package/MissingConfig-stderr.txt b/Tests/RunCMake/find_package/MissingConfig-stderr.txt index 0d14dcb..1eae0bb 100644 --- a/Tests/CMakeCommands/find_package/MissingConfig-stderr.txt +++ b/Tests/RunCMake/find_package/MissingConfig-stderr.txt @@ -11,3 +11,9 @@ CMake Warning at MissingConfig.cmake:1 \(find_package\): been installed. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) + + +CMake Warning at MissingConfig.cmake:2 \(message\): + This warning must be reachable. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/find_package/MissingConfig.cmake b/Tests/RunCMake/find_package/MissingConfig.cmake new file mode 100644 index 0000000..238e7e4 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingConfig.cmake @@ -0,0 +1,2 @@ +find_package(NotHere CONFIG) +message(WARNING "This warning must be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingConfigOneName-stderr.txt b/Tests/RunCMake/find_package/MissingConfigOneName-stderr.txt index 10e71fa..10e71fa 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigOneName-stderr.txt +++ b/Tests/RunCMake/find_package/MissingConfigOneName-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MissingConfigOneName.cmake b/Tests/RunCMake/find_package/MissingConfigOneName.cmake index 11676a9..11676a9 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigOneName.cmake +++ b/Tests/RunCMake/find_package/MissingConfigOneName.cmake diff --git a/Tests/CMakeCommands/find_package/MissingConfigRequired-result.txt b/Tests/RunCMake/find_package/MissingConfigRequired-result.txt index d00491f..d00491f 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigRequired-result.txt +++ b/Tests/RunCMake/find_package/MissingConfigRequired-result.txt diff --git a/Tests/CMakeCommands/find_package/MissingConfigRequired-stderr.txt b/Tests/RunCMake/find_package/MissingConfigRequired-stderr.txt index 56325d8..2ba774a 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigRequired-stderr.txt +++ b/Tests/RunCMake/find_package/MissingConfigRequired-stderr.txt @@ -10,4 +10,4 @@ CMake Error at MissingConfigRequired.cmake:1 \(find_package\): "NotHere" provides a separate development package or SDK, be sure it has been installed. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/find_package/MissingConfigRequired.cmake b/Tests/RunCMake/find_package/MissingConfigRequired.cmake new file mode 100644 index 0000000..0ae6702 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingConfigRequired.cmake @@ -0,0 +1,2 @@ +find_package(NotHere CONFIG REQUIRED) +message(FATAL_ERROR "This error must not be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingConfigVersion-stderr.txt b/Tests/RunCMake/find_package/MissingConfigVersion-stderr.txt index 2f5086e..2f5086e 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigVersion-stderr.txt +++ b/Tests/RunCMake/find_package/MissingConfigVersion-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MissingConfigVersion.cmake b/Tests/RunCMake/find_package/MissingConfigVersion.cmake index ac35a79..ac35a79 100644 --- a/Tests/CMakeCommands/find_package/MissingConfigVersion.cmake +++ b/Tests/RunCMake/find_package/MissingConfigVersion.cmake diff --git a/Tests/CMakeCommands/find_package/MissingModule-stderr.txt b/Tests/RunCMake/find_package/MissingModule-stderr.txt index 71b5eae..2ad460f 100644 --- a/Tests/CMakeCommands/find_package/MissingModule-stderr.txt +++ b/Tests/RunCMake/find_package/MissingModule-stderr.txt @@ -19,3 +19,8 @@ CMake Warning \(dev\) at MissingModule.cmake:1 \(find_package\): Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) This warning is for project developers. Use -Wno-dev to suppress it. + +CMake Warning at MissingModule.cmake:2 \(message\): + This warning must be reachable. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/find_package/MissingModule.cmake b/Tests/RunCMake/find_package/MissingModule.cmake new file mode 100644 index 0000000..76bcef2 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingModule.cmake @@ -0,0 +1,2 @@ +find_package(NotHere MODULE) +message(WARNING "This warning must be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingModuleRequired-result.txt b/Tests/RunCMake/find_package/MissingModuleRequired-result.txt index d00491f..d00491f 100644 --- a/Tests/CMakeCommands/find_package/MissingModuleRequired-result.txt +++ b/Tests/RunCMake/find_package/MissingModuleRequired-result.txt diff --git a/Tests/CMakeCommands/find_package/MissingModuleRequired-stderr.txt b/Tests/RunCMake/find_package/MissingModuleRequired-stderr.txt index c3cd350..fec05f1 100644 --- a/Tests/CMakeCommands/find_package/MissingModuleRequired-stderr.txt +++ b/Tests/RunCMake/find_package/MissingModuleRequired-stderr.txt @@ -18,4 +18,4 @@ CMake Warning \(dev\) at MissingModuleRequired.cmake:1 \(find_package\): Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) -This warning is for project developers. Use -Wno-dev to suppress it. +This warning is for project developers. Use -Wno-dev to suppress it.$ diff --git a/Tests/RunCMake/find_package/MissingModuleRequired.cmake b/Tests/RunCMake/find_package/MissingModuleRequired.cmake new file mode 100644 index 0000000..897eda6 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingModuleRequired.cmake @@ -0,0 +1,2 @@ +find_package(NotHere MODULE REQUIRED) +message(FATAL_ERROR "This error must not be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingNormal-stderr.txt b/Tests/RunCMake/find_package/MissingNormal-stderr.txt index e5cbd97..f4c6fba 100644 --- a/Tests/CMakeCommands/find_package/MissingNormal-stderr.txt +++ b/Tests/RunCMake/find_package/MissingNormal-stderr.txt @@ -15,3 +15,9 @@ CMake Warning at MissingNormal.cmake:1 \(find_package\): been installed. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) + + +CMake Warning at MissingNormal.cmake:2 \(message\): + This warning must be reachable. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/find_package/MissingNormal.cmake b/Tests/RunCMake/find_package/MissingNormal.cmake new file mode 100644 index 0000000..fb90e01 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingNormal.cmake @@ -0,0 +1,2 @@ +find_package(NotHere) +message(WARNING "This warning must be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingNormalRequired-result.txt b/Tests/RunCMake/find_package/MissingNormalRequired-result.txt index d00491f..d00491f 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalRequired-result.txt +++ b/Tests/RunCMake/find_package/MissingNormalRequired-result.txt diff --git a/Tests/CMakeCommands/find_package/MissingNormalRequired-stderr.txt b/Tests/RunCMake/find_package/MissingNormalRequired-stderr.txt index ac52aec..7bb7902 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalRequired-stderr.txt +++ b/Tests/RunCMake/find_package/MissingNormalRequired-stderr.txt @@ -14,4 +14,4 @@ CMake Error at MissingNormalRequired.cmake:1 \(find_package\): "NotHere" provides a separate development package or SDK, be sure it has been installed. Call Stack \(most recent call first\): - CMakeLists.txt:3 \(include\) + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/find_package/MissingNormalRequired.cmake b/Tests/RunCMake/find_package/MissingNormalRequired.cmake new file mode 100644 index 0000000..33353d8 --- /dev/null +++ b/Tests/RunCMake/find_package/MissingNormalRequired.cmake @@ -0,0 +1,2 @@ +find_package(NotHere REQUIRED) +message(FATAL_ERROR "This error must not be reachable.") diff --git a/Tests/CMakeCommands/find_package/MissingNormalVersion-stderr.txt b/Tests/RunCMake/find_package/MissingNormalVersion-stderr.txt index 36de800..36de800 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalVersion-stderr.txt +++ b/Tests/RunCMake/find_package/MissingNormalVersion-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MissingNormalVersion.cmake b/Tests/RunCMake/find_package/MissingNormalVersion.cmake index 2d9ce4e..2d9ce4e 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalVersion.cmake +++ b/Tests/RunCMake/find_package/MissingNormalVersion.cmake diff --git a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleNew-stderr.txt b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew-stderr.txt index d34f23c..d34f23c 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleNew-stderr.txt +++ b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleNew.cmake b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew.cmake index 0211249..0211249 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleNew.cmake +++ b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleNew.cmake diff --git a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleOld-stderr.txt b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld-stderr.txt index b336b56..b336b56 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleOld-stderr.txt +++ b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleOld.cmake b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld.cmake index 1c4a775..1c4a775 100644 --- a/Tests/CMakeCommands/find_package/MissingNormalWarnNoModuleOld.cmake +++ b/Tests/RunCMake/find_package/MissingNormalWarnNoModuleOld.cmake diff --git a/Tests/RunCMake/find_package/MixedModeOptions-result.txt b/Tests/RunCMake/find_package/MixedModeOptions-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/find_package/MixedModeOptions-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/CMakeCommands/find_package/MixedModeOptions-stderr.txt b/Tests/RunCMake/find_package/MixedModeOptions-stderr.txt index b867022..b867022 100644 --- a/Tests/CMakeCommands/find_package/MixedModeOptions-stderr.txt +++ b/Tests/RunCMake/find_package/MixedModeOptions-stderr.txt diff --git a/Tests/CMakeCommands/find_package/MixedModeOptions.cmake b/Tests/RunCMake/find_package/MixedModeOptions.cmake index 7f78ee0..7f78ee0 100644 --- a/Tests/CMakeCommands/find_package/MixedModeOptions.cmake +++ b/Tests/RunCMake/find_package/MixedModeOptions.cmake diff --git a/Tests/RunCMake/find_package/RunCMakeTest.cmake b/Tests/RunCMake/find_package/RunCMakeTest.cmake new file mode 100644 index 0000000..ba57f99 --- /dev/null +++ b/Tests/RunCMake/find_package/RunCMakeTest.cmake @@ -0,0 +1,14 @@ +include(RunCMake) + +run_cmake(MissingNormal) +run_cmake(MissingNormalRequired) +run_cmake(MissingNormalVersion) +run_cmake(MissingNormalWarnNoModuleOld) +run_cmake(MissingNormalWarnNoModuleNew) +run_cmake(MissingModule) +run_cmake(MissingModuleRequired) +run_cmake(MissingConfig) +run_cmake(MissingConfigOneName) +run_cmake(MissingConfigRequired) +run_cmake(MissingConfigVersion) +run_cmake(MixedModeOptions) diff --git a/Tests/SBCS/CMakeLists.txt b/Tests/SBCS/CMakeLists.txt new file mode 100644 index 0000000..b3c3c2c --- /dev/null +++ b/Tests/SBCS/CMakeLists.txt @@ -0,0 +1,6 @@ +# a SBCS test case +project (SBCS) + +add_definitions(-D_SBCS) + +add_executable (SBCS SBCS.cxx) diff --git a/Tests/SBCS/SBCS.cxx b/Tests/SBCS/SBCS.cxx new file mode 100644 index 0000000..6ce2c9f --- /dev/null +++ b/Tests/SBCS/SBCS.cxx @@ -0,0 +1,22 @@ +// Test to verify that _SBCS being defined causes CharacterSet to be set to 0 (Single Byte Character Set) + +int main () +{ +#ifdef _UNICODE + bool UnicodeSet=true; +#else + bool UnicodeSet=false; +#endif + +#ifdef _MBCS + bool MBCSSet=true; +#else + bool MBCSSet=false; +#endif + + // if neither _UNICODE nor _MBCS is set, CharacterSet must be set to SBCS. + bool SBCSSet=(!UnicodeSet && !MBCSSet); + + // Reverse boolean to indicate error case correctly + return !SBCSSet; +} diff --git a/Utilities/KWIML/test/test_INT_format.h.in b/Utilities/KWIML/test/test_INT_format.h.in index 72a62f2..a8ea263 100644 --- a/Utilities/KWIML/test/test_INT_format.h.in +++ b/Utilities/KWIML/test/test_INT_format.h.in @@ -18,15 +18,13 @@ # define LANG "C " #endif -#define VALUE(T, U) \ - (@KWIML@_INT_##T)((@KWIML@_INT_##U)0xab << \ - ((sizeof(@KWIML@_INT_##T)-1)<<3)) \ +#define VALUE(T, U) (T)((U)0xab << ((sizeof(T)-1)<<3)) -#define TEST_C(C, V, PRI, T, U) \ +#define TEST_C_(C, V, PRI, T, U) \ { \ - @KWIML@_INT_##T const x = VALUE(T, U); \ - @KWIML@_INT_##T y = @KWIML@_INT_##C(V); \ - printf(LANG "@KWIML@_INT_" #C ":" \ + T const x = VALUE(T, U); \ + T y = C(V); \ + printf(LANG #C ":" \ " expression [%"@KWIML@_INT_PRI##PRI"]," \ " literal [%"@KWIML@_INT_PRI##PRI"]", x, y); \ if(x == y) \ @@ -40,9 +38,9 @@ } \ } -#define TEST_PRI(PRI, T, U, STR) \ +#define TEST_PRI_(PRI, T, U, STR) \ { \ - @KWIML@_INT_##T const x = VALUE(T, U); \ + T const x = VALUE(T, U); \ char const* str = STR; \ sprintf(buf, "%"@KWIML@_INT_PRI##PRI, x); \ printf(LANG "@KWIML@_INT_PRI" #PRI ":" \ @@ -58,11 +56,11 @@ } \ } -#define TEST_SCN(SCN, T, U, STR) TEST_SCN2(SCN, SCN, T, U, STR) -#define TEST_SCN2(PRI, SCN, T, U, STR) \ +#define TEST_SCN_(SCN, T, U, STR) TEST_SCN2_(SCN, SCN, T, U, STR) +#define TEST_SCN2_(PRI, SCN, T, U, STR) \ { \ - @KWIML@_INT_##T const x = VALUE(T, U); \ - @KWIML@_INT_##T y; \ + T const x = VALUE(T, U); \ + T y; \ char const* str = STR; \ if(sscanf(str, "%"@KWIML@_INT_SCN##SCN, &y) != 1) \ { \ @@ -82,10 +80,24 @@ } \ } -#define TEST(FMT, T, U, STR) TEST2(FMT, FMT, T, U, STR) -#define TEST2(PRI, SCN, T, U, STR) \ - TEST_PRI(PRI, T, U, STR) \ - TEST_SCN2(PRI, SCN, T, U, STR) +#define TEST_(FMT, T, U, STR) TEST2_(FMT, FMT, T, U, STR) +#define TEST2_(PRI, SCN, T, U, STR) \ + TEST_PRI_(PRI, T, U, STR) \ + TEST_SCN2_(PRI, SCN, T, U, STR) + +/* Concatenate T and U now to avoid expanding them. */ +#define TEST(FMT, T, U, STR) \ + TEST_(FMT, @KWIML@_INT_##T, @KWIML@_INT_##U, STR) +#define TEST2(PRI, SCN, T, U, STR) \ + TEST2_(PRI, SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR) +#define TEST_C(C, V, PRI, T, U) \ + TEST_C_(@KWIML@_INT_##C, V, PRI, @KWIML@_INT_##T, @KWIML@_INT_##U) +#define TEST_PRI(PRI, T, U, STR) \ + TEST_PRI_(PRI, @KWIML@_INT_##T, @KWIML@_INT_##U, STR) +#define TEST_SCN(SCN, T, U, STR) \ + TEST_SCN_(SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR) +#define TEST_SCN2(PRI, SCN, T, U, STR) \ + TEST_SCN2_(PRI, SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR) static int test_INT_format(void) { diff --git a/Utilities/Release/Cygwin/cygwin-setup.hint.in b/Utilities/Release/Cygwin/cygwin-setup.hint.in index 9706c0d..a2532fc 100644 --- a/Utilities/Release/Cygwin/cygwin-setup.hint.in +++ b/Utilities/Release/Cygwin/cygwin-setup.hint.in @@ -1,5 +1,5 @@ # CMake setup.hint file for cygwin setup.exe program -category: Devel -requires: @CMAKE_NCURSES_VERSION@ cygwin -sdesc: "A cross platform build manager" -ldesc: "CMake is a cross platform build manager. It allows you to specify build parameters for C and C++ programs in a cross platform manner. For cygwin Makefiles will be generated. CMake is also capable of generating microsoft project files, nmake, and borland makefiles. CMake can also perform system inspection operations like finding installed libraries and header files." +category: Devel +requires: libgcc1 libidn11 @CMAKE_NCURSES_VERSION@ libstdc++6 +sdesc: "A cross platform build manager" +ldesc: "CMake is a cross platform build manager. It allows you to specify build parameters for C and C++ programs in a cross platform manner. For cygwin Makefiles will be generated. CMake is also capable of generating microsoft project files, nmake, and borland makefiles. CMake can also perform system inspection operations like finding installed libraries and header files." diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt index 29ce25d6..caa44f1 100644 --- a/Utilities/cmcurl/CMakeLists.txt +++ b/Utilities/cmcurl/CMakeLists.txt @@ -126,9 +126,9 @@ IF(CURL_MALLOC_DEBUG) ENDIF(CURL_MALLOC_DEBUG) # On windows preload settings -IF(WIN32) +IF(WIN32 AND NOT MINGW) INCLUDE(${LIBCURL_SOURCE_DIR}/Platforms/WindowsCache.cmake) -ENDIF(WIN32) +ENDIF() # This macro checks if the symbol exists in the library and if it # does, it appends library to the list. |