diff options
103 files changed, 4055 insertions, 1268 deletions
diff --git a/Help/command/enable_language.rst b/Help/command/enable_language.rst index fb49b44..fdc44f2 100644 --- a/Help/command/enable_language.rst +++ b/Help/command/enable_language.rst @@ -1,7 +1,6 @@ enable_language --------------- - -Enable a language (CXX/C/Fortran/etc) +Enable a language (CXX/C/OBJC/OBJCXX/Fortran/etc) .. code-block:: cmake @@ -10,7 +9,7 @@ Enable a language (CXX/C/Fortran/etc) Enables support for the named language in CMake. This is the same as the :command:`project` command but does not create any of the extra variables that are created by the project command. Example languages -are ``CXX``, ``C``, ``CUDA``, ``Fortran``, and ``ASM``. +are ``CXX``, ``C``, ``CUDA``, ``OBJC``, ``OBJCXX``, ``Fortran``, and ``ASM``. If enabling ``ASM``, enable it last so that CMake can check whether compilers for other languages like ``C`` work for assembly too. diff --git a/Help/command/project.rst b/Help/command/project.rst index baf18be..3951456 100644 --- a/Help/command/project.rst +++ b/Help/command/project.rst @@ -87,7 +87,8 @@ The options are: Can also be specified without ``LANGUAGES`` keyword per the first, short signature. Selects which programming languages are needed to build the project. - Supported languages include ``C``, ``CXX`` (i.e. C++), ``CUDA``, ``Fortran``, and ``ASM``. + Supported languages include ``C``, ``CXX`` (i.e. C++), ``CUDA``, + ``OBJC`` (i.e. Objective-C), ``OBJCXX``, ``Fortran``, and ``ASM``. By default ``C`` and ``CXX`` are enabled if no language options are given. Specify language ``NONE``, or use the ``LANGUAGES`` keyword and list no languages, to skip enabling any languages. diff --git a/Help/manual/cmake-generator-expressions.7.rst b/Help/manual/cmake-generator-expressions.7.rst index c0449fb..6e7f9b5 100644 --- a/Help/manual/cmake-generator-expressions.7.rst +++ b/Help/manual/cmake-generator-expressions.7.rst @@ -130,6 +130,16 @@ Variable Queries ``1`` if the CMake's compiler id of the CUDA compiler matches any one of the entries in ``compiler_ids``, otherwise ``0``. See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +``$<OBJC_COMPILER_ID:compiler_ids>`` + where ``compiler_ids`` is a comma-separated list. + ``1`` if the CMake's compiler id of the Objective-C compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +``$<OBJCXX_COMPILER_ID:compiler_ids>`` + where ``compiler_ids`` is a comma-separated list. + ``1`` if the CMake's compiler id of the Objective-C++ compiler matches any one + of the entries in ``compiler_ids``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. ``$<Fortran_COMPILER_ID:compiler_ids>`` where ``compiler_ids`` is a comma-separated list. ``1`` if the CMake's compiler id of the Fortran compiler matches any one @@ -144,6 +154,12 @@ Variable Queries ``$<CUDA_COMPILER_VERSION:version>`` ``1`` if the version of the CXX compiler matches ``version``, otherwise ``0``. See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +``$<OBJC_COMPILER_VERSION:version>`` + ``1`` if the version of the OBJC compiler matches ``version``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +``$<OBJCXX_COMPILER_VERSION:version>`` + ``1`` if the version of the OBJCXX compiler matches ``version``, otherwise ``0``. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. ``$<Fortran_COMPILER_VERSION:version>`` ``1`` if the version of the Fortran compiler matches ``version``, otherwise ``0``. See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. @@ -401,6 +417,12 @@ Variable Queries ``$<CUDA_COMPILER_ID>`` The CMake's compiler id of the CUDA compiler used. See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +``$<OBJC_COMPILER_ID>`` + The CMake's compiler id of the OBJC compiler used. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. +``$<OBJCXX_COMPILER_ID>`` + The CMake's compiler id of the OBJCXX compiler used. + See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. ``$<Fortran_COMPILER_ID>`` The CMake's compiler id of the Fortran compiler used. See also the :variable:`CMAKE_<LANG>_COMPILER_ID` variable. @@ -413,6 +435,12 @@ Variable Queries ``$<CUDA_COMPILER_VERSION>`` The version of the CUDA compiler used. See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +``$<OBJC_COMPILER_VERSION>`` + The version of the OBJC compiler used. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. +``$<OBJCXX_COMPILER_VERSION>`` + The version of the OBJCXX compiler used. + See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. ``$<Fortran_COMPILER_VERSION>`` The version of the Fortran compiler used. See also the :variable:`CMAKE_<LANG>_COMPILER_VERSION` variable. diff --git a/Help/manual/cmake-modules.7.rst b/Help/manual/cmake-modules.7.rst index fc4bfdc..c60dc40 100644 --- a/Help/manual/cmake-modules.7.rst +++ b/Help/manual/cmake-modules.7.rst @@ -36,6 +36,12 @@ These modules are loaded using the :command:`include` command. /module/CheckIncludeFiles /module/CheckLanguage /module/CheckLibraryExists + /module/CheckOBJCCompilerFlag + /module/CheckOBJCSourceCompiles + /module/CheckOBJCSourceRuns + /module/CheckOBJCXXCompilerFlag + /module/CheckOBJCXXSourceCompiles + /module/CheckOBJCXXSourceRuns /module/CheckPIESupported /module/CheckPrototypeDefinition /module/CheckStructHasMember diff --git a/Help/module/CheckOBJCCompilerFlag.rst b/Help/module/CheckOBJCCompilerFlag.rst new file mode 100644 index 0000000..e4bd6fd --- /dev/null +++ b/Help/module/CheckOBJCCompilerFlag.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCCompilerFlag.cmake diff --git a/Help/module/CheckOBJCSourceCompiles.rst b/Help/module/CheckOBJCSourceCompiles.rst new file mode 100644 index 0000000..d4a1484 --- /dev/null +++ b/Help/module/CheckOBJCSourceCompiles.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCSourceCompiles.cmake diff --git a/Help/module/CheckOBJCSourceRuns.rst b/Help/module/CheckOBJCSourceRuns.rst new file mode 100644 index 0000000..c72f0db --- /dev/null +++ b/Help/module/CheckOBJCSourceRuns.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCSourceRuns.cmake diff --git a/Help/module/CheckOBJCXXCompilerFlag.rst b/Help/module/CheckOBJCXXCompilerFlag.rst new file mode 100644 index 0000000..1518a48 --- /dev/null +++ b/Help/module/CheckOBJCXXCompilerFlag.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCXXCompilerFlag.cmake diff --git a/Help/module/CheckOBJCXXSourceCompiles.rst b/Help/module/CheckOBJCXXSourceCompiles.rst new file mode 100644 index 0000000..a1c8ae9 --- /dev/null +++ b/Help/module/CheckOBJCXXSourceCompiles.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCXXSourceCompiles.cmake diff --git a/Help/module/CheckOBJCXXSourceRuns.rst b/Help/module/CheckOBJCXXSourceRuns.rst new file mode 100644 index 0000000..5198e1b --- /dev/null +++ b/Help/module/CheckOBJCXXSourceRuns.rst @@ -0,0 +1 @@ +.. cmake-module:: ../../Modules/CheckOBJCXXSourceRuns.cmake diff --git a/Help/release/dev/FPHSA-reason-failure-message.rst b/Help/release/dev/FPHSA-reason-failure-message.rst new file mode 100644 index 0000000..419c3ba --- /dev/null +++ b/Help/release/dev/FPHSA-reason-failure-message.rst @@ -0,0 +1,5 @@ +FPHSA-reason-failure-message +---------------------------- + +* Modules :module:`FindPackageHandleStandardArgs` gains the capability to + specify a message giving the reason for the failure. diff --git a/Help/release/dev/objective-c-cxx.rst b/Help/release/dev/objective-c-cxx.rst new file mode 100644 index 0000000..218af4e --- /dev/null +++ b/Help/release/dev/objective-c-cxx.rst @@ -0,0 +1,9 @@ +Objective C/C++ +--------------- + +* CMake learned to support the Objective C (``OBJC``) and Objective C++ + (``OBJCXX``) languages. They may be enabled via the :command:`project` + and :command:`enable_language` commands. When ``OBJC`` or ``OBJCXX`` + is enabled, source files with the ``.m`` or ``.mm``, respectively, + will be compiled as Objective C or C++. Otherwise they will be treated + as plain C++ sources as they were before. diff --git a/Modules/CMakeCXXCompiler.cmake.in b/Modules/CMakeCXXCompiler.cmake.in index e7f0e70..ef65021 100644 --- a/Modules/CMakeCXXCompiler.cmake.in +++ b/Modules/CMakeCXXCompiler.cmake.in @@ -42,8 +42,17 @@ if(CMAKE_COMPILER_IS_MINGW) set(MINGW 1) endif() set(CMAKE_CXX_COMPILER_ID_RUN 1) +set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;m;mm;CPP) set(CMAKE_CXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O;obj;OBJ;def;DEF;rc;RC) -set(CMAKE_CXX_SOURCE_FILE_EXTENSIONS C;M;c++;cc;cpp;cxx;mm;CPP) + +foreach (lang OBJC OBJCXX) + if (CMAKE_${lang}_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_${lang}_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_CXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() + endif() +endforeach() + set(CMAKE_CXX_LINKER_PREFERENCE 30) set(CMAKE_CXX_LINKER_PREFERENCE_PROPAGATES 1) diff --git a/Modules/CMakeDetermineOBJCCompiler.cmake b/Modules/CMakeDetermineOBJCCompiler.cmake new file mode 100644 index 0000000..ad13eab --- /dev/null +++ b/Modules/CMakeDetermineOBJCCompiler.cmake @@ -0,0 +1,189 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +# determine the compiler to use for Objective-C programs +# NOTE, a generator may set CMAKE_OBJC_COMPILER before +# loading this file to force a compiler. +# use environment variable OBJC first if defined by user, next use +# the cmake variable CMAKE_GENERATOR_OBJC which can be defined by a generator +# as a default compiler +# +# Sets the following variables: +# CMAKE_OBJC_COMPILER +# CMAKE_AR +# CMAKE_RANLIB +# CMAKE_COMPILER_IS_GNUOBJC +# CMAKE_COMPILER_IS_CLANGOBJC +# +# If not already set before, it also sets +# _CMAKE_TOOLCHAIN_PREFIX + +include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) + +# Load system-specific compiler preferences for this language. +include(Platform/${CMAKE_SYSTEM_NAME}-Determine-OBJC OPTIONAL) +include(Platform/${CMAKE_SYSTEM_NAME}-OBJC OPTIONAL) +if(NOT CMAKE_OBJC_COMPILER_NAMES) + set(CMAKE_OBJC_COMPILER_NAMES clang) +endif() + +if("${CMAKE_GENERATOR}" MATCHES "Xcode") + set(CMAKE_OBJC_COMPILER_XCODE_TYPE sourcecode.c.objc) +else() + if(NOT CMAKE_OBJC_COMPILER) + set(CMAKE_OBJC_COMPILER_INIT NOTFOUND) + + # prefer the environment variable OBJC + if($ENV{OBJC} MATCHES ".+") + get_filename_component(CMAKE_OBJC_COMPILER_INIT $ENV{OBJC} PROGRAM PROGRAM_ARGS CMAKE_OBJC_FLAGS_ENV_INIT) + if(CMAKE_OBJC_FLAGS_ENV_INIT) + set(CMAKE_OBJC_COMPILER_ARG1 "${CMAKE_OBJC_FLAGS_ENV_INIT}" CACHE STRING "First argument to Objective-C compiler") + endif() + if(NOT EXISTS ${CMAKE_OBJC_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable OBJC:\n$ENV{OBJC}.") + endif() + endif() + + # next try prefer the compiler specified by the generator + if(CMAKE_GENERATOR_OBJC) + if(NOT CMAKE_OBJC_COMPILER_INIT) + set(CMAKE_OBJC_COMPILER_INIT ${CMAKE_GENERATOR_OBJC}) + endif() + endif() + + # finally list compilers to try + if(NOT CMAKE_OBJC_COMPILER_INIT) + set(CMAKE_OBJC_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}cc ${_CMAKE_TOOLCHAIN_PREFIX}gcc clang) + endif() + + _cmake_find_compiler(OBJC) + + else() + # we only get here if CMAKE_OBJC_COMPILER was specified using -D or a pre-made CMakeCache.txt + # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE + # if CMAKE_OBJC_COMPILER is a list of length 2, use the first item as + # CMAKE_OBJC_COMPILER and the 2nd one as CMAKE_OBJC_COMPILER_ARG1 + + list(LENGTH CMAKE_OBJC_COMPILER _CMAKE_OBJC_COMPILER_LIST_LENGTH) + if("${_CMAKE_OBJC_COMPILER_LIST_LENGTH}" EQUAL 2) + list(GET CMAKE_OBJC_COMPILER 1 CMAKE_OBJC_COMPILER_ARG1) + list(GET CMAKE_OBJC_COMPILER 0 CMAKE_OBJC_COMPILER) + endif() + + # if a compiler was specified by the user but without path, + # now try to find it with the full path + # if it is found, force it into the cache, + # if not, don't overwrite the setting (which was given by the user) with "NOTFOUND" + # if the C compiler already had a path, reuse it for searching the CXX compiler + get_filename_component(_CMAKE_USER_OBJC_COMPILER_PATH "${CMAKE_OBJC_COMPILER}" PATH) + if(NOT _CMAKE_USER_OBJC_COMPILER_PATH) + find_program(CMAKE_OBJC_COMPILER_WITH_PATH NAMES ${CMAKE_OBJC_COMPILER}) + if(CMAKE_OBJC_COMPILER_WITH_PATH) + set(CMAKE_OBJC_COMPILER ${CMAKE_OBJC_COMPILER_WITH_PATH} CACHE STRING "Objective-C compiler" FORCE) + endif() + unset(CMAKE_OBJC_COMPILER_WITH_PATH CACHE) + endif() + endif() + mark_as_advanced(CMAKE_OBJC_COMPILER) + + # Each entry in this list is a set of extra flags to try + # adding to the compile line to see if it helps produce + # a valid identification file. + set(CMAKE_OBJC_COMPILER_ID_TEST_FLAGS_FIRST) + set(CMAKE_OBJC_COMPILER_ID_TEST_FLAGS + # Try compiling to an object file only. + "-c" + + ) +endif() + +# Build a small source file to identify the compiler. +if(NOT CMAKE_OBJC_COMPILER_ID_RUN) + set(CMAKE_OBJC_COMPILER_ID_RUN 1) + + # Try to identify the compiler. + set(CMAKE_OBJC_COMPILER_ID) + file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in + CMAKE_OBJC_COMPILER_ID_PLATFORM_CONTENT) + + # Match the link line from xcodebuild output of the form + # Ld ... + # ... + # /path/to/cc ...CompilerIdOBJC/... + # to extract the compiler front-end for the language. + set(CMAKE_OBJC_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdOBJC/(\\./)?(CompilerIdOBJC.(framework|xctest)/)?CompilerIdOBJC[ \t\n\\\"]") + set(CMAKE_OBJC_COMPILER_ID_TOOL_MATCH_INDEX 2) + + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) + CMAKE_DETERMINE_COMPILER_ID(OBJC OBJCCFLAGS CMakeOBJCCompilerId.m) + + # Set old compiler and platform id variables. + if(CMAKE_OBJC_COMPILER_ID STREQUAL "GNU") + set(CMAKE_COMPILER_IS_GNUOBJC 1) + endif() + if(CMAKE_OBJC_COMPILER_ID STREQUAL "Clang") + set(CMAKE_COMPILER_IS_CLANGOBJC 1) + endif() +endif() + +if (NOT _CMAKE_TOOLCHAIN_LOCATION) + get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_OBJC_COMPILER}" PATH) +endif () + +# If we have a gcc cross compiler, they have usually some prefix, like +# e.g. powerpc-linux-gcc, arm-elf-gcc or i586-mingw32msvc-gcc, optionally +# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2). +# The other tools of the toolchain usually have the same prefix +# NAME_WE cannot be used since then this test will fail for names like +# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be +# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-" +if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) + + if(CMAKE_OBJC_COMPILER_ID MATCHES "GNU|Clang|QCC") + get_filename_component(COMPILER_BASENAME "${CMAKE_OBJC_COMPILER}" NAME) + if (COMPILER_BASENAME MATCHES "^(.+-)(clang|g?cc)(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$") + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1}) + set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5}) + elseif(CMAKE_OBJC_COMPILER_ID MATCHES "Clang") + if(CMAKE_OBJC_COMPILER_TARGET) + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_OBJC_COMPILER_TARGET}-) + endif() + elseif(COMPILER_BASENAME MATCHES "qcc(\\.exe)?$") + if(CMAKE_OBJC_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)?") + set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-) + endif() + endif () + + # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils + # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.) + if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$") + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1}) + endif () + endif() + +endif () + +set(_CMAKE_PROCESSING_LANGUAGE "OBJC") +include(CMakeFindBinUtils) +include(Compiler/${CMAKE_OBJC_COMPILER_ID}-FindBinUtils OPTIONAL) +unset(_CMAKE_PROCESSING_LANGUAGE) + +if(CMAKE_OBJC_COMPILER_ARCHITECTURE_ID) + set(_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID + "set(CMAKE_OBJC_COMPILER_ARCHITECTURE_ID ${CMAKE_OBJC_COMPILER_ARCHITECTURE_ID})") +else() + set(_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID "") +endif() + +if(CMAKE_OBJC_XCODE_ARCHS) + set(SET_CMAKE_XCODE_ARCHS + "set(CMAKE_XCODE_ARCHS \"${CMAKE_OBJC_XCODE_ARCHS}\")") +endif() + +# configure variables set in this file for fast reload later on +configure_file(${CMAKE_ROOT}/Modules/CMakeOBJCCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake + @ONLY + ) +set(CMAKE_OBJC_COMPILER_ENV_VAR "OBJC") diff --git a/Modules/CMakeDetermineOBJCXXCompiler.cmake b/Modules/CMakeDetermineOBJCXXCompiler.cmake new file mode 100644 index 0000000..60fcbb3 --- /dev/null +++ b/Modules/CMakeDetermineOBJCXXCompiler.cmake @@ -0,0 +1,197 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +# determine the compiler to use for Objective-C++ programs +# NOTE, a generator may set CMAKE_OBJCXX_COMPILER before +# loading this file to force a compiler. +# use environment variable OBJCXX first if defined by user, next use +# the cmake variable CMAKE_GENERATOR_OBJCXX which can be defined by a generator +# as a default compiler +# If the internal cmake variable _CMAKE_TOOLCHAIN_PREFIX is set, this is used +# as prefix for the tools (e.g. arm-elf-g++, arm-elf-ar etc.) +# +# Sets the following variables: +# CMAKE_OBJCXX_COMPILER +# CMAKE_COMPILER_IS_GNUOBJCXX +# CMAKE_COMPILER_IS_CLANGOBJCXX +# CMAKE_AR +# CMAKE_RANLIB +# +# If not already set before, it also sets +# _CMAKE_TOOLCHAIN_PREFIX + +include(${CMAKE_ROOT}/Modules/CMakeDetermineCompiler.cmake) + +# Load system-specific compiler preferences for this language. +include(Platform/${CMAKE_SYSTEM_NAME}-Determine-OBJCXX OPTIONAL) +include(Platform/${CMAKE_SYSTEM_NAME}-OBJCXX OPTIONAL) +if(NOT CMAKE_OBJCXX_COMPILER_NAMES) + set(CMAKE_OBJCXX_COMPILER_NAMES clang++) +endif() + +if("${CMAKE_GENERATOR}" MATCHES "Xcode") + set(CMAKE_OBJCXX_COMPILER_XCODE_TYPE sourcecode.cpp.objcpp) +else() + if(NOT CMAKE_OBJCXX_COMPILER) + set(CMAKE_OBJCXX_COMPILER_INIT NOTFOUND) + + # prefer the environment variable OBJCXX + if($ENV{OBJCXX} MATCHES ".+") + get_filename_component(CMAKE_OBJCXX_COMPILER_INIT $ENV{OBJCXX} PROGRAM PROGRAM_ARGS CMAKE_OBJCXX_FLAGS_ENV_INIT) + if(CMAKE_OBJCXX_FLAGS_ENV_INIT) + set(CMAKE_OBJCXX_COMPILER_ARG1 "${CMAKE_OBJCXX_FLAGS_ENV_INIT}" CACHE STRING "First argument to Objective-C++ compiler") + endif() + if(NOT EXISTS ${CMAKE_OBJCXX_COMPILER_INIT}) + message(FATAL_ERROR "Could not find compiler set in environment variable OBJCXX:\n$ENV{OBJCXX}.\n${CMAKE_OBJCXX_COMPILER_INIT}") + endif() + endif() + + # next prefer the generator specified compiler + if(CMAKE_GENERATOR_OBJCXX) + if(NOT CMAKE_OBJCXX_COMPILER_INIT) + set(CMAKE_OBJCXX_COMPILER_INIT ${CMAKE_GENERATOR_OBJCXX}) + endif() + endif() + + # finally list compilers to try + if(NOT CMAKE_OBJCXX_COMPILER_INIT) + set(CMAKE_OBJCXX_COMPILER_LIST ${_CMAKE_TOOLCHAIN_PREFIX}c++ ${_CMAKE_TOOLCHAIN_PREFIX}g++ clang++) + endif() + + _cmake_find_compiler(OBJCXX) + + else() + # we only get here if CMAKE_OBJCXX_COMPILER was specified using -D or a pre-made CMakeCache.txt + # (e.g. via ctest) or set in CMAKE_TOOLCHAIN_FILE + # if CMAKE_OBJCXX_COMPILER is a list of length 2, use the first item as + # CMAKE_OBJCXX_COMPILER and the 2nd one as CMAKE_OBJCXX_COMPILER_ARG1 + + list(LENGTH CMAKE_OBJCXX_COMPILER _CMAKE_OBJCXX_COMPILER_LIST_LENGTH) + if("${_CMAKE_OBJCXX_COMPILER_LIST_LENGTH}" EQUAL 2) + list(GET CMAKE_OBJCXX_COMPILER 1 CMAKE_OBJCXX_COMPILER_ARG1) + list(GET CMAKE_OBJCXX_COMPILER 0 CMAKE_OBJCXX_COMPILER) + endif() + + # if a compiler was specified by the user but without path, + # now try to find it with the full path + # if it is found, force it into the cache, + # if not, don't overwrite the setting (which was given by the user) with "NOTFOUND" + # if the C compiler already had a path, reuse it for searching the CXX compiler + get_filename_component(_CMAKE_USER_OBJCXX_COMPILER_PATH "${CMAKE_OBJCXX_COMPILER}" PATH) + if(NOT _CMAKE_USER_OBJCXX_COMPILER_PATH) + find_program(CMAKE_OBJCXX_COMPILER_WITH_PATH NAMES ${CMAKE_OBJCXX_COMPILER}) + if(CMAKE_OBJCXX_COMPILER_WITH_PATH) + set(CMAKE_OBJCXX_COMPILER ${CMAKE_OBJCXX_COMPILER_WITH_PATH} CACHE STRING "Objective-C++ compiler" FORCE) + endif() + unset(CMAKE_OBJCXX_COMPILER_WITH_PATH CACHE) + endif() + + endif() + mark_as_advanced(CMAKE_OBJCXX_COMPILER) + + # Each entry in this list is a set of extra flags to try + # adding to the compile line to see if it helps produce + # a valid identification file. + set(CMAKE_OBJCXX_COMPILER_ID_TEST_FLAGS_FIRST) + set(CMAKE_OBJCXX_COMPILER_ID_TEST_FLAGS + # Try compiling to an object file only. + "-c" + + # ARMClang need target options + "--target=arm-arm-none-eabi -mcpu=cortex-m3" + ) +endif() + +# Build a small source file to identify the compiler. +if(NOT CMAKE_OBJCXX_COMPILER_ID_RUN) + set(CMAKE_OBJCXX_COMPILER_ID_RUN 1) + + # Try to identify the compiler. + set(CMAKE_OBJCXX_COMPILER_ID) + file(READ ${CMAKE_ROOT}/Modules/CMakePlatformId.h.in + CMAKE_OBJCXX_COMPILER_ID_PLATFORM_CONTENT) + + # Match the link line from xcodebuild output of the form + # Ld ... + # ... + # /path/to/cc ...CompilerIdOBJCXX/... + # to extract the compiler front-end for the language. + set(CMAKE_OBJCXX_COMPILER_ID_TOOL_MATCH_REGEX "\nLd[^\n]*(\n[ \t]+[^\n]*)*\n[ \t]+([^ \t\r\n]+)[^\r\n]*-o[^\r\n]*CompilerIdOBJCXX/(\\./)?(CompilerIdOBJCXX.(framework|xctest)/)?CompilerIdOBJCXX[ \t\n\\\"]") + set(CMAKE_OBJCXX_COMPILER_ID_TOOL_MATCH_INDEX 2) + + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerId.cmake) + CMAKE_DETERMINE_COMPILER_ID(OBJCXX OBJCXXFLAGS CMakeOBJCXXCompilerId.mm) + + # Set old compiler and platform id variables. + if(CMAKE_OBJCXX_COMPILER_ID MATCHES "GNU") + set(CMAKE_COMPILER_IS_GNUOBJCXX 1) + endif() + if(CMAKE_OBJCXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_COMPILER_IS_CLANGOBJCXX 1) + endif() +endif() + +if (NOT _CMAKE_TOOLCHAIN_LOCATION) + get_filename_component(_CMAKE_TOOLCHAIN_LOCATION "${CMAKE_OBJCXX_COMPILER}" PATH) +endif () + +# if we have a g++ cross compiler, they have usually some prefix, like +# e.g. powerpc-linux-g++, arm-elf-g++ or i586-mingw32msvc-g++ , optionally +# with a 3-component version number at the end (e.g. arm-eabi-gcc-4.5.2). +# The other tools of the toolchain usually have the same prefix +# NAME_WE cannot be used since then this test will fail for names like +# "arm-unknown-nto-qnx6.3.0-gcc.exe", where BASENAME would be +# "arm-unknown-nto-qnx6" instead of the correct "arm-unknown-nto-qnx6.3.0-" + + +if (CMAKE_CROSSCOMPILING AND NOT _CMAKE_TOOLCHAIN_PREFIX) + + if("${CMAKE_OBJCXX_COMPILER_ID}" MATCHES "GNU|Clang|QCC") + get_filename_component(COMPILER_BASENAME "${CMAKE_OBJCXX_COMPILER}" NAME) + if (COMPILER_BASENAME MATCHES "^(.+-)(clan)?[gc]\\+\\+(-[0-9]+(\\.[0-9]+)*)?(-[^.]+)?(\\.exe)?$") + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1}) + set(_CMAKE_COMPILER_SUFFIX ${CMAKE_MATCH_5}) + elseif("${CMAKE_OBJCXX_COMPILER_ID}" MATCHES "Clang") + if(CMAKE_OBJCXX_COMPILER_TARGET) + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_OBJCXX_COMPILER_TARGET}-) + endif() + elseif(COMPILER_BASENAME MATCHES "QCC(\\.exe)?$") + if(CMAKE_OBJCXX_COMPILER_TARGET MATCHES "gcc_nto([a-z0-9]+_[0-9]+|[^_le]+)(le)") + set(_CMAKE_TOOLCHAIN_PREFIX nto${CMAKE_MATCH_1}-) + endif() + endif () + + # if "llvm-" is part of the prefix, remove it, since llvm doesn't have its own binutils + # but uses the regular ar, objcopy, etc. (instead of llvm-objcopy etc.) + if ("${_CMAKE_TOOLCHAIN_PREFIX}" MATCHES "(.+-)?llvm-$") + set(_CMAKE_TOOLCHAIN_PREFIX ${CMAKE_MATCH_1}) + endif () + endif() + +endif () + +set(_CMAKE_PROCESSING_LANGUAGE "OBJCXX") +include(CMakeFindBinUtils) +include(Compiler/${CMAKE_OBJCXX_COMPILER_ID}-FindBinUtils OPTIONAL) +unset(_CMAKE_PROCESSING_LANGUAGE) + +if(CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID) + set(_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID + "set(CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID ${CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID})") +else() + set(_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID "") +endif() + +if(CMAKE_OBJCXX_XCODE_ARCHS) + set(SET_CMAKE_XCODE_ARCHS + "set(CMAKE_XCODE_ARCHS \"${CMAKE_OBJCXX_XCODE_ARCHS}\")") +endif() + +# configure all variables set in this file +configure_file(${CMAKE_ROOT}/Modules/CMakeOBJCXXCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake + @ONLY + ) + +set(CMAKE_OBJCXX_COMPILER_ENV_VAR "OBJCXX") diff --git a/Modules/CMakeOBJCCompiler.cmake.in b/Modules/CMakeOBJCCompiler.cmake.in new file mode 100644 index 0000000..1555517 --- /dev/null +++ b/Modules/CMakeOBJCCompiler.cmake.in @@ -0,0 +1,69 @@ +set(CMAKE_OBJC_COMPILER "@CMAKE_OBJC_COMPILER@") +set(CMAKE_OBJC_COMPILER_ARG1 "@CMAKE_OBJC_COMPILER_ARG1@") +set(CMAKE_OBJC_COMPILER_ID "@CMAKE_OBJC_COMPILER_ID@") +set(CMAKE_OBJC_COMPILER_VERSION "@CMAKE_OBJC_COMPILER_VERSION@") +set(CMAKE_OBJC_COMPILER_VERSION_INTERNAL "@CMAKE_OBJC_COMPILER_VERSION_INTERNAL@") +set(CMAKE_OBJC_COMPILER_WRAPPER "@CMAKE_OBJC_COMPILER_WRAPPER@") +set(CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJC_STANDARD_COMPUTED_DEFAULT@") +set(CMAKE_OBJC_COMPILE_FEATURES "@CMAKE_OBJC_COMPILE_FEATURES@") +set(CMAKE_OBJC90_COMPILE_FEATURES "@CMAKE_OBJC90_COMPILE_FEATURES@") +set(CMAKE_OBJC99_COMPILE_FEATURES "@CMAKE_OBJC99_COMPILE_FEATURES@") +set(CMAKE_OBJC11_COMPILE_FEATURES "@CMAKE_OBJC11_COMPILE_FEATURES@") + +set(CMAKE_OBJC_PLATFORM_ID "@CMAKE_OBJC_PLATFORM_ID@") +set(CMAKE_OBJC_SIMULATE_ID "@CMAKE_OBJC_SIMULATE_ID@") +set(CMAKE_OBJC_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJC_COMPILER_FRONTEND_VARIANT@") +set(CMAKE_OBJC_SIMULATE_VERSION "@CMAKE_OBJC_SIMULATE_VERSION@") +@_SET_CMAKE_OBJC_COMPILER_ARCHITECTURE_ID@ +@SET_CMAKE_XCODE_ARCHS@ +set(CMAKE_AR "@CMAKE_AR@") +set(CMAKE_OBJC_COMPILER_AR "@CMAKE_OBJC_COMPILER_AR@") +set(CMAKE_RANLIB "@CMAKE_RANLIB@") +set(CMAKE_OBJC_COMPILER_RANLIB "@CMAKE_OBJC_COMPILER_RANLIB@") +set(CMAKE_LINKER "@CMAKE_LINKER@") +set(CMAKE_MT "@CMAKE_MT@") +set(CMAKE_COMPILER_IS_GNUOBJC @CMAKE_COMPILER_IS_GNUOBJC@) +set(CMAKE_OBJC_COMPILER_LOADED 1) +set(CMAKE_OBJC_COMPILER_WORKS @CMAKE_OBJC_COMPILER_WORKS@) +set(CMAKE_OBJC_ABI_COMPILED @CMAKE_OBJC_ABI_COMPILED@) + +set(CMAKE_OBJC_COMPILER_ENV_VAR "OBJC") + +set(CMAKE_OBJC_COMPILER_ID_RUN 1) +set(CMAKE_OBJC_SOURCE_FILE_EXTENSIONS m) +set(CMAKE_OBJC_IGNORE_EXTENSIONS h;H;o;O) +set(CMAKE_OBJC_LINKER_PREFERENCE 5) + +foreach (lang C CXX OBJCXX) + foreach(extension IN LISTS CMAKE_OBJC_SOURCE_FILE_EXTENSIONS) + if (CMAKE_${lang}_COMPILER_ID_RUN) + list(REMOVE_ITEM CMAKE_${lang}_SOURCE_FILE_EXTENSIONS ${extension}) + endif() + endforeach() +endforeach() + +# Save compiler ABI information. +set(CMAKE_OBJC_SIZEOF_DATA_PTR "@CMAKE_OBJC_SIZEOF_DATA_PTR@") +set(CMAKE_OBJC_COMPILER_ABI "@CMAKE_OBJC_COMPILER_ABI@") +set(CMAKE_OBJC_LIBRARY_ARCHITECTURE "@CMAKE_OBJC_LIBRARY_ARCHITECTURE@") + +if(CMAKE_OBJC_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_OBJC_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_OBJC_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_OBJC_COMPILER_ABI}") +endif() + +if(CMAKE_OBJC_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_OBJC_LIBRARY_ARCHITECTURE@") +endif() + +@CMAKE_OBJC_COMPILER_CUSTOM_CODE@ +@CMAKE_OBJC_SYSROOT_FLAG_CODE@ +@CMAKE_OBJC_OSX_DEPLOYMENT_TARGET_FLAG_CODE@ + +set(CMAKE_OBJC_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_INCLUDE_DIRECTORIES@") +set(CMAKE_OBJC_IMPLICIT_LINK_LIBRARIES "@CMAKE_OBJC_IMPLICIT_LINK_LIBRARIES@") +set(CMAKE_OBJC_IMPLICIT_LINK_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_LINK_DIRECTORIES@") +set(CMAKE_OBJC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_OBJC_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@") diff --git a/Modules/CMakeOBJCCompilerABI.m b/Modules/CMakeOBJCCompilerABI.m new file mode 100644 index 0000000..8fa8511 --- /dev/null +++ b/Modules/CMakeOBJCCompilerABI.m @@ -0,0 +1,20 @@ +#ifdef __cplusplus +# error "A C++ compiler has been selected for Objective-C." +#endif + +/*--------------------------------------------------------------------------*/ + +#include "CMakeCompilerABI.h" + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + int require = 0; + require += info_sizeof_dptr[argc]; +#if defined(ABI_ID) + require += info_abi[argc]; +#endif + (void)argv; + return require; +} diff --git a/Modules/CMakeOBJCCompilerId.m.in b/Modules/CMakeOBJCCompilerId.m.in new file mode 100644 index 0000000..2b8aa30 --- /dev/null +++ b/Modules/CMakeOBJCCompilerId.m.in @@ -0,0 +1,63 @@ +#ifdef __cplusplus +# error "An Objective-C++ compiler has been selected for Objective-C." +#endif + +@CMAKE_OBJC_COMPILER_ID_CONTENT@ + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +@CMAKE_OBJC_COMPILER_ID_PLATFORM_CONTENT@ +@CMAKE_OBJC_COMPILER_ID_ERROR_FOR_TEST@ + +#if !defined(__STDC__) +# if (defined(_MSC_VER) && !defined(__clang__)) \ + || (defined(__ibmxl__) || defined(__IBMC__)) +# define C_DIALECT "90" +# else +# define C_DIALECT +# endif +#elif __STDC_VERSION__ >= 201000L +# define C_DIALECT "11" +#elif __STDC_VERSION__ >= 199901L +# define C_DIALECT "99" +#else +# define C_DIALECT "90" +#endif +const char* info_language_dialect_default = + "INFO" ":" "dialect_default[" C_DIALECT "]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; + require += info_arch[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/Modules/CMakeOBJCInformation.cmake b/Modules/CMakeOBJCInformation.cmake new file mode 100644 index 0000000..2baad4a --- /dev/null +++ b/Modules/CMakeOBJCInformation.cmake @@ -0,0 +1,188 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +# This file sets the basic flags for the Objective-C language in CMake. +# It also loads the available platform file for the system-compiler +# if it exists. +# It also loads a system - compiler - processor (or target hardware) +# specific file, which is mainly useful for crosscompiling and embedded systems. + +include(CMakeLanguageInformation) + +# some compilers use different extensions (e.g. sdcc uses .rel) +# so set the extension here first so it can be overridden by the compiler specific file +set(CMAKE_OBJC_OUTPUT_EXTENSION .o) + +if(NOT CMAKE_INCLUDE_FLAG_OBJC) + set(CMAKE_INCLUDE_FLAG_OBJC ${CMAKE_INCLUDE_FLAG_C}) +endif() + +set(_INCLUDED_FILE 0) + +# Load compiler-specific information. +if(CMAKE_OBJC_COMPILER_ID) + include(Compiler/${CMAKE_OBJC_COMPILER_ID}-OBJC OPTIONAL) +endif() + +set(CMAKE_BASE_NAME) +get_filename_component(CMAKE_BASE_NAME "${CMAKE_OBJC_COMPILER}" NAME_WE) +if(CMAKE_COMPILER_IS_GNUOBJC) + set(CMAKE_BASE_NAME gcc) +endif() + + +# load a hardware specific file, mostly useful for embedded compilers +if(CMAKE_SYSTEM_PROCESSOR) + if(CMAKE_OBJC_COMPILER_ID) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJC_COMPILER_ID}-OBJC-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) + endif() + if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL) + endif () +endif() + + +# load the system- and compiler specific files +if(CMAKE_OBJC_COMPILER_ID) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJC_COMPILER_ID}-OBJC + OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) +endif() +if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} + OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) +endif () + +# load any compiler-wrapper specific information +if (CMAKE_OBJC_COMPILER_WRAPPER) + __cmake_include_compiler_wrapper(OBJC) +endif () + +# We specify the compiler information in the system file for some +# platforms, but this language may not have been enabled when the file +# was first included. Include it again to get the language info. +# Remove this when all compiler info is removed from system files. +if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL) +endif () + +if(CMAKE_OBJC_SIZEOF_DATA_PTR) + foreach(f ${CMAKE_OBJC_ABI_FILES}) + include(${f}) + endforeach() + unset(CMAKE_OBJC_ABI_FILES) +endif() + +# This should be included before the _INIT variables are +# used to initialize the cache. Since the rule variables +# have if blocks on them, users can still define them here. +# But, it should still be after the platform file so changes can +# be made to those values. + +if(CMAKE_USER_MAKE_RULES_OVERRIDE) + # Save the full path of the file so try_compile can use it. + include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override) + set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}") +endif() + +if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC) + # Save the full path of the file so try_compile can use it. + include(${CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC} RESULT_VARIABLE _override) + set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJC "${_override}") +endif() + + +# for most systems a module is the same as a shared library +# so unless the variable CMAKE_MODULE_EXISTS is set just +# copy the values from the LIBRARY variables +if(NOT CMAKE_MODULE_EXISTS) + set(CMAKE_SHARED_MODULE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS}) + set(CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS}) +endif() + +set(CMAKE_OBJC_FLAGS_INIT "$ENV{OBJCFLAGS} ${CMAKE_OBJC_FLAGS_INIT}") + +cmake_initialize_per_config_variable(CMAKE_OBJC_FLAGS "Flags used by the Objective-C compiler") + +if(CMAKE_OBJC_STANDARD_LIBRARIES_INIT) + set(CMAKE_OBJC_STANDARD_LIBRARIES "${CMAKE_OBJC_STANDARD_LIBRARIES_INIT}" + CACHE STRING "Libraries linked by default with all Objective-C applications.") + mark_as_advanced(CMAKE_OBJC_STANDARD_LIBRARIES) +endif() + +include(CMakeCommonLanguageInclude) + +# now define the following rule variables + +# CMAKE_OBJC_CREATE_SHARED_LIBRARY +# CMAKE_OBJC_CREATE_SHARED_MODULE +# CMAKE_OBJC_COMPILE_OBJECT +# CMAKE_OBJC_LINK_EXECUTABLE + +# variables supplied by the generator at use time +# <TARGET> +# <TARGET_BASE> the target without the suffix +# <OBJECTS> +# <OBJECT> +# <LINK_LIBRARIES> +# <FLAGS> +# <LINK_FLAGS> + +# Objective-C compiler information +# <CMAKE_OBJC_COMPILER> +# <CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS> +# <CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS> +# <CMAKE_OBJC_LINK_FLAGS> + +# Static library tools +# <CMAKE_AR> +# <CMAKE_RANLIB> + + +# create an Objective-C shared library +if(NOT CMAKE_OBJC_CREATE_SHARED_LIBRARY) + set(CMAKE_OBJC_CREATE_SHARED_LIBRARY + "<CMAKE_OBJC_COMPILER> <CMAKE_SHARED_LIBRARY_OBJC_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>") +endif() + +# create an Objective-C shared module just copy the shared library rule +if(NOT CMAKE_OBJC_CREATE_SHARED_MODULE) + set(CMAKE_OBJC_CREATE_SHARED_MODULE ${CMAKE_OBJC_CREATE_SHARED_LIBRARY}) +endif() + +# Create an static archive incrementally for large object file counts. +# If CMAKE_OBJC_CREATE_STATIC_LIBRARY is set it will override these. +if(NOT DEFINED CMAKE_OBJC_ARCHIVE_CREATE) + set(CMAKE_OBJC_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>") +endif() +if(NOT DEFINED CMAKE_OBJC_ARCHIVE_APPEND) + set(CMAKE_OBJC_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>") +endif() +if(NOT DEFINED CMAKE_OBJC_ARCHIVE_FINISH) + set(CMAKE_OBJC_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>") +endif() + +# compile an Objective-C file into an object file +if(NOT CMAKE_OBJC_COMPILE_OBJECT) + set(CMAKE_OBJC_COMPILE_OBJECT + "<CMAKE_OBJC_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>") +endif() + +if(NOT CMAKE_OBJC_LINK_EXECUTABLE) + set(CMAKE_OBJC_LINK_EXECUTABLE + "<CMAKE_OBJC_COMPILER> <FLAGS> <CMAKE_OBJC_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") +endif() + +if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG) + set(CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG}) +endif() + +if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG_SEP) + set(CMAKE_EXECUTABLE_RUNTIME_OBJC_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG_SEP}) +endif() + +if(NOT CMAKE_EXECUTABLE_RPATH_LINK_OBJC_FLAG) + set(CMAKE_EXECUTABLE_RPATH_LINK_OBJC_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJC_FLAG}) +endif() + +set(CMAKE_OBJC_INFORMATION_LOADED 1) diff --git a/Modules/CMakeOBJCXXCompiler.cmake.in b/Modules/CMakeOBJCXXCompiler.cmake.in new file mode 100644 index 0000000..b6452c4 --- /dev/null +++ b/Modules/CMakeOBJCXXCompiler.cmake.in @@ -0,0 +1,79 @@ +set(CMAKE_OBJCXX_COMPILER "@CMAKE_OBJCXX_COMPILER@") +set(CMAKE_OBJCXX_COMPILER_ARG1 "@CMAKE_OBJCXX_COMPILER_ARG1@") +set(CMAKE_OBJCXX_COMPILER_ID "@CMAKE_OBJCXX_COMPILER_ID@") +set(CMAKE_OBJCXX_COMPILER_VERSION "@CMAKE_OBJCXX_COMPILER_VERSION@") +set(CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL "@CMAKE_OBJCXX_COMPILER_VERSION_INTERNAL@") +set(CMAKE_OBJCXX_COMPILER_WRAPPER "@CMAKE_OBJCXX_COMPILER_WRAPPER@") +set(CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT "@CMAKE_OBJCXX_STANDARD_COMPUTED_DEFAULT@") +set(CMAKE_OBJCXX_COMPILE_FEATURES "@CMAKE_OBJCXX_COMPILE_FEATURES@") +set(CMAKE_OBJCXX98_COMPILE_FEATURES "@CMAKE_OBJCXX98_COMPILE_FEATURES@") +set(CMAKE_OBJCXX11_COMPILE_FEATURES "@CMAKE_OBJCXX11_COMPILE_FEATURES@") +set(CMAKE_OBJCXX14_COMPILE_FEATURES "@CMAKE_OBJCXX14_COMPILE_FEATURES@") +set(CMAKE_OBJCXX17_COMPILE_FEATURES "@CMAKE_OBJCXX17_COMPILE_FEATURES@") +set(CMAKE_OBJCXX20_COMPILE_FEATURES "@CMAKE_OBJCXX20_COMPILE_FEATURES@") + +set(CMAKE_OBJCXX_PLATFORM_ID "@CMAKE_OBJCXX_PLATFORM_ID@") +set(CMAKE_OBJCXX_SIMULATE_ID "@CMAKE_OBJCXX_SIMULATE_ID@") +set(CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT "@CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT@") +set(CMAKE_OBJCXX_SIMULATE_VERSION "@CMAKE_OBJCXX_SIMULATE_VERSION@") +@_SET_CMAKE_OBJCXX_COMPILER_ARCHITECTURE_ID@ +@SET_CMAKE_XCODE_ARCHS@ +set(CMAKE_AR "@CMAKE_AR@") +set(CMAKE_OBJCXX_COMPILER_AR "@CMAKE_OBJCXX_COMPILER_AR@") +set(CMAKE_RANLIB "@CMAKE_RANLIB@") +set(CMAKE_OBJCXX_COMPILER_RANLIB "@CMAKE_OBJCXX_COMPILER_RANLIB@") +set(CMAKE_LINKER "@CMAKE_LINKER@") +set(CMAKE_MT "@CMAKE_MT@") +set(CMAKE_COMPILER_IS_GNUOBJCXX @CMAKE_COMPILER_IS_GNUOBJCXX@) +set(CMAKE_OBJCXX_COMPILER_LOADED 1) +set(CMAKE_OBJCXX_COMPILER_WORKS @CMAKE_OBJCXX_COMPILER_WORKS@) +set(CMAKE_OBJCXX_ABI_COMPILED @CMAKE_OBJCXX_ABI_COMPILED@) + +set(CMAKE_OBJCXX_COMPILER_ENV_VAR "OBJCXX") + +set(CMAKE_OBJCXX_COMPILER_ID_RUN 1) +set(CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS M;m;mm) +set(CMAKE_OBJCXX_IGNORE_EXTENSIONS inl;h;hpp;HPP;H;o;O) + +if (CMAKE_OBJC_COMPILER_ID_RUN) + foreach(extension IN LISTS CMAKE_OBJC_SOURCE_FILE_EXTENSIONS) + list(REMOVE_ITEM CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS ${extension}) + endforeach() +endif() + +foreach (lang C CXX OBJC) + foreach(extension IN LISTS CMAKE_OBJCXX_SOURCE_FILE_EXTENSIONS) + if (CMAKE_${lang}_COMPILER_ID_RUN) + list(REMOVE_ITEM CMAKE_${lang}_SOURCE_FILE_EXTENSIONS ${extension}) + endif() + endforeach() +endforeach() + +set(CMAKE_OBJCXX_LINKER_PREFERENCE 25) +set(CMAKE_OBJCXX_LINKER_PREFERENCE_PROPAGATES 1) + +# Save compiler ABI information. +set(CMAKE_OBJCXX_SIZEOF_DATA_PTR "@CMAKE_OBJCXX_SIZEOF_DATA_PTR@") +set(CMAKE_OBJCXX_COMPILER_ABI "@CMAKE_OBJCXX_COMPILER_ABI@") +set(CMAKE_OBJCXX_LIBRARY_ARCHITECTURE "@CMAKE_OBJCXX_LIBRARY_ARCHITECTURE@") + +if(CMAKE_OBJCXX_SIZEOF_DATA_PTR) + set(CMAKE_SIZEOF_VOID_P "${CMAKE_OBJCXX_SIZEOF_DATA_PTR}") +endif() + +if(CMAKE_OBJCXX_COMPILER_ABI) + set(CMAKE_INTERNAL_PLATFORM_ABI "${CMAKE_OBJCXX_COMPILER_ABI}") +endif() + +if(CMAKE_OBJCXX_LIBRARY_ARCHITECTURE) + set(CMAKE_LIBRARY_ARCHITECTURE "@CMAKE_OBJCXX_LIBRARY_ARCHITECTURE@") +endif() + +@CMAKE_OBJCXX_COMPILER_CUSTOM_CODE@ +@CMAKE_OBJCXX_SYSROOT_FLAG_CODE@ +@CMAKE_OBJCXX_OSX_DEPLOYMENT_TARGET_FLAG_CODE@ + +set(CMAKE_OBJCXX_IMPLICIT_INCLUDE_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_INCLUDE_DIRECTORIES@") +set(CMAKE_OBJCXX_IMPLICIT_LINK_LIBRARIES "@CMAKE_OBJCXX_IMPLICIT_LINK_LIBRARIES@") +set(CMAKE_OBJCXX_IMPLICIT_LINK_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_LINK_DIRECTORIES@") +set(CMAKE_OBJCXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES "@CMAKE_OBJCXX_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES@") diff --git a/Modules/CMakeOBJCXXCompilerABI.mm b/Modules/CMakeOBJCXXCompilerABI.mm new file mode 100644 index 0000000..288a58c --- /dev/null +++ b/Modules/CMakeOBJCXXCompilerABI.mm @@ -0,0 +1,20 @@ +#ifndef __cplusplus +# error "A C compiler has been selected for Objective-C++." +#endif + +/*--------------------------------------------------------------------------*/ + +#include "CMakeCompilerABI.h" + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + int require = 0; + require += info_sizeof_dptr[argc]; +#if defined(ABI_ID) + require += info_abi[argc]; +#endif + (void)argv; + return require; +} diff --git a/Modules/CMakeOBJCXXCompilerId.mm.in b/Modules/CMakeOBJCXXCompilerId.mm.in new file mode 100644 index 0000000..fe04de1 --- /dev/null +++ b/Modules/CMakeOBJCXXCompilerId.mm.in @@ -0,0 +1,68 @@ +/* This source file must have a .cpp extension so that all C++ compilers + recognize the extension without flags. Borland does not know .cxx for + example. */ +#ifndef __cplusplus +# error "An Objective-C compiler has been selected for Objective-C++." +#endif + +@CMAKE_OBJCXX_COMPILER_ID_CONTENT@ + +/* Construct the string literal in pieces to prevent the source from + getting matched. Store it in a pointer rather than an array + because some compilers will just produce instructions to fill the + array rather than assigning a pointer to a static array. */ +char const* info_compiler = "INFO" ":" "compiler[" COMPILER_ID "]"; +#ifdef SIMULATE_ID +char const* info_simulate = "INFO" ":" "simulate[" SIMULATE_ID "]"; +#endif + +#ifdef __QNXNTO__ +char const* qnxnto = "INFO" ":" "qnxnto[]"; +#endif + +@CMAKE_OBJCXX_COMPILER_ID_PLATFORM_CONTENT@ +@CMAKE_OBJCXX_COMPILER_ID_ERROR_FOR_TEST@ + +#if defined(_MSC_VER) && defined(_MSVC_LANG) +#define CXX_STD _MSVC_LANG +#else +#define CXX_STD __cplusplus +#endif + +const char* info_language_dialect_default = "INFO" ":" "dialect_default[" +#if CXX_STD > 201703L + "20" +#elif CXX_STD >= 201703L + "17" +#elif CXX_STD >= 201402L + "14" +#elif CXX_STD >= 201103L + "11" +#else + "98" +#endif +"]"; + +/*--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + int require = 0; + require += info_compiler[argc]; + require += info_platform[argc]; +#ifdef COMPILER_VERSION_MAJOR + require += info_version[argc]; +#endif +#ifdef COMPILER_VERSION_INTERNAL + require += info_version_internal[argc]; +#endif +#ifdef SIMULATE_ID + require += info_simulate[argc]; +#endif +#ifdef SIMULATE_VERSION_MAJOR + require += info_simulate_version[argc]; +#endif + require += info_language_dialect_default[argc]; + (void)argv; + return require; +} diff --git a/Modules/CMakeOBJCXXInformation.cmake b/Modules/CMakeOBJCXXInformation.cmake new file mode 100644 index 0000000..3f55b01 --- /dev/null +++ b/Modules/CMakeOBJCXXInformation.cmake @@ -0,0 +1,273 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +# This file sets the basic flags for the Objective-C++ language in CMake. +# It also loads the available platform file for the system-compiler +# if it exists. +# It also loads a system - compiler - processor (or target hardware) +# specific file, which is mainly useful for crosscompiling and embedded systems. + +include(CMakeLanguageInformation) + +# some compilers use different extensions (e.g. sdcc uses .rel) +# so set the extension here first so it can be overridden by the compiler specific file +set(CMAKE_OBJCXX_OUTPUT_EXTENSION .o) + +set(_INCLUDED_FILE 0) + +# Load compiler-specific information. +if(CMAKE_OBJCXX_COMPILER_ID) + include(Compiler/${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX OPTIONAL) +endif() + +set(CMAKE_BASE_NAME) +get_filename_component(CMAKE_BASE_NAME "${CMAKE_OBJCXX_COMPILER}" NAME_WE) +# since the gnu compiler has several names force g++ +if(CMAKE_COMPILER_IS_GNUOBJCXX) + set(CMAKE_BASE_NAME g++) +endif() + + +# load a hardware specific file, mostly useful for embedded compilers +if(CMAKE_SYSTEM_PROCESSOR) + if(CMAKE_OBJCXX_COMPILER_ID) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) + endif() + if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME}-${CMAKE_SYSTEM_PROCESSOR} OPTIONAL) + endif () +endif() + +# load the system- and compiler specific files +if(CMAKE_OBJCXX_COMPILER_ID) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_OBJCXX_COMPILER_ID}-OBJCXX OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) +endif() +if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_EFFECTIVE_SYSTEM_NAME}-${CMAKE_BASE_NAME} OPTIONAL + RESULT_VARIABLE _INCLUDED_FILE) +endif () + +# load any compiler-wrapper specific information +if (CMAKE_OBJCXX_COMPILER_WRAPPER) + __cmake_include_compiler_wrapper(OBJCXX) +endif () + +# We specify the compiler information in the system file for some +# platforms, but this language may not have been enabled when the file +# was first included. Include it again to get the language info. +# Remove this when all compiler info is removed from system files. +if (NOT _INCLUDED_FILE) + include(Platform/${CMAKE_SYSTEM_NAME} OPTIONAL) +endif () + +if(CMAKE_OBJCXX_SIZEOF_DATA_PTR) + foreach(f ${CMAKE_OBJCXX_ABI_FILES}) + include(${f}) + endforeach() + unset(CMAKE_OBJCXX_ABI_FILES) +endif() + +# This should be included before the _INIT variables are +# used to initialize the cache. Since the rule variables +# have if blocks on them, users can still define them here. +# But, it should still be after the platform file so changes can +# be made to those values. + +if(CMAKE_USER_MAKE_RULES_OVERRIDE) + # Save the full path of the file so try_compile can use it. + include(${CMAKE_USER_MAKE_RULES_OVERRIDE} RESULT_VARIABLE _override) + set(CMAKE_USER_MAKE_RULES_OVERRIDE "${_override}") +endif() + +if(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX) + # Save the full path of the file so try_compile can use it. + include(${CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX} RESULT_VARIABLE _override) + set(CMAKE_USER_MAKE_RULES_OVERRIDE_OBJCXX "${_override}") +endif() + + +# Create a set of shared library variable specific to Objective-C++ +# For 90% of the systems, these are the same flags as the Objective-C versions +# so if these are not set just copy the flags from the Objective-C version +if(NOT CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS) + set(CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS}) +endif() + +if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIC) + set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIC ${CMAKE_OBJC_COMPILE_OPTIONS_PIC}) +endif() + +if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_PIE) + set(CMAKE_OBJCXX_COMPILE_OPTIONS_PIE ${CMAKE_OBJC_COMPILE_OPTIONS_PIE}) +endif() +if(NOT CMAKE_OBJCXX_LINK_OPTIONS_PIE) + set(CMAKE_OBJCXX_LINK_OPTIONS_PIE ${CMAKE_OBJC_LINK_OPTIONS_PIE}) +endif() +if(NOT CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE) + set(CMAKE_OBJCXX_LINK_OPTIONS_NO_PIE ${CMAKE_OBJC_LINK_OPTIONS_NO_PIE}) +endif() + +if(NOT CMAKE_OBJCXX_COMPILE_OPTIONS_DLL) + set(CMAKE_OBJCXX_COMPILE_OPTIONS_DLL ${CMAKE_OBJC_COMPILE_OPTIONS_DLL}) +endif() + +if(NOT CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS) + set(CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJC_FLAGS}) +endif() + +if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS) + set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_LINK_OBJC_FLAGS}) +endif() + +if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG) + set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG}) +endif() + +if(NOT CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP) + set(CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJC_FLAG_SEP}) +endif() + +if(NOT CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG) + set(CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJC_FLAG}) +endif() + +if(NOT DEFINED CMAKE_EXE_EXPORTS_OBJCXX_FLAG) + set(CMAKE_EXE_EXPORTS_OBJCXX_FLAG ${CMAKE_EXE_EXPORTS_OBJC_FLAG}) +endif() + +if(NOT DEFINED CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG) + set(CMAKE_SHARED_LIBRARY_SONAME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_SONAME_OBJC_FLAG}) +endif() + +if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG) + set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG}) +endif() + +if(NOT CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP) + set(CMAKE_EXECUTABLE_RUNTIME_OBJCXX_FLAG_SEP ${CMAKE_SHARED_LIBRARY_RUNTIME_OBJCXX_FLAG_SEP}) +endif() + +if(NOT CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG) + set(CMAKE_EXECUTABLE_RPATH_LINK_OBJCXX_FLAG ${CMAKE_SHARED_LIBRARY_RPATH_LINK_OBJCXX_FLAG}) +endif() + +if(NOT DEFINED CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH) + set(CMAKE_SHARED_LIBRARY_LINK_OBJCXX_WITH_RUNTIME_PATH ${CMAKE_SHARED_LIBRARY_LINK_OBJC_WITH_RUNTIME_PATH}) +endif() + +if(NOT CMAKE_INCLUDE_FLAG_OBJCXX) + set(CMAKE_INCLUDE_FLAG_OBJCXX ${CMAKE_INCLUDE_FLAG_C}) +endif() + +# for most systems a module is the same as a shared library +# so unless the variable CMAKE_MODULE_EXISTS is set just +# copy the values from the LIBRARY variables +if(NOT CMAKE_MODULE_EXISTS) + set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS}) + set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS}) +endif() + +# repeat for modules +if(NOT CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS) + set(CMAKE_SHARED_MODULE_CREATE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_CREATE_OBJC_FLAGS}) +endif() + +if(NOT CMAKE_SHARED_MODULE_OBJCXX_FLAGS) + set(CMAKE_SHARED_MODULE_OBJCXX_FLAGS ${CMAKE_SHARED_MODULE_OBJC_FLAGS}) +endif() + +# Initialize OBJCXX link type selection flags from OBJC versions. +foreach(type SHARED_LIBRARY SHARED_MODULE EXE) + if(NOT CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS) + set(CMAKE_${type}_LINK_STATIC_OBJCXX_FLAGS + ${CMAKE_${type}_LINK_STATIC_OBJC_FLAGS}) + endif() + if(NOT CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS) + set(CMAKE_${type}_LINK_DYNAMIC_OBJCXX_FLAGS + ${CMAKE_${type}_LINK_DYNAMIC_OBJC_FLAGS}) + endif() +endforeach() + +# add the flags to the cache based +# on the initial values computed in the platform/*.cmake files +# use _INIT variables so that this only happens the first time +# and you can set these flags in the cmake cache +set(CMAKE_OBJCXX_FLAGS_INIT "$ENV{OBJCXXFLAGS} ${CMAKE_OBJCXX_FLAGS_INIT}") + +cmake_initialize_per_config_variable(CMAKE_OBJCXX_FLAGS "Flags used by the Objective-C++ compiler") + +if(CMAKE_OBJCXX_STANDARD_LIBRARIES_INIT) + set(CMAKE_OBJCXX_STANDARD_LIBRARIES "${CMAKE_OBJCXX_STANDARD_LIBRARIES_INIT}" + CACHE STRING "Libraries linked by default with all Objective-C++ applications.") + mark_as_advanced(CMAKE_OBJCXX_STANDARD_LIBRARIES) +endif() + +include(CMakeCommonLanguageInclude) + +# now define the following rules: +# CMAKE_OBJCXX_CREATE_SHARED_LIBRARY +# CMAKE_OBJCXX_CREATE_SHARED_MODULE +# CMAKE_OBJCXX_COMPILE_OBJECT +# CMAKE_OBJCXX_LINK_EXECUTABLE + +# variables supplied by the generator at use time +# <TARGET> +# <TARGET_BASE> the target without the suffix +# <OBJECTS> +# <OBJECT> +# <LINK_LIBRARIES> +# <FLAGS> +# <LINK_FLAGS> + +# Objective-C++ compiler information +# <CMAKE_OBJCXX_COMPILER> +# <CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS> +# <CMAKE_OBJCXX_SHARED_MODULE_CREATE_FLAGS> +# <CMAKE_OBJCXX_LINK_FLAGS> + +# Static library tools +# <CMAKE_AR> +# <CMAKE_RANLIB> + + +# create a shared Objective-C++ library +if(NOT CMAKE_OBJCXX_CREATE_SHARED_LIBRARY) + set(CMAKE_OBJCXX_CREATE_SHARED_LIBRARY + "<CMAKE_OBJCXX_COMPILER> <CMAKE_SHARED_LIBRARY_OBJCXX_FLAGS> <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>") +endif() + +# create an Objective-C++ shared module copy the shared library rule by default +if(NOT CMAKE_OBJCXX_CREATE_SHARED_MODULE) + set(CMAKE_OBJCXX_CREATE_SHARED_MODULE ${CMAKE_OBJCXX_CREATE_SHARED_LIBRARY}) +endif() + + +# Create a static archive incrementally for large object file counts. +# If CMAKE_OBJCXX_CREATE_STATIC_LIBRARY is set it will override these. +if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_CREATE) + set(CMAKE_OBJCXX_ARCHIVE_CREATE "<CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>") +endif() +if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_APPEND) + set(CMAKE_OBJCXX_ARCHIVE_APPEND "<CMAKE_AR> q <TARGET> <LINK_FLAGS> <OBJECTS>") +endif() +if(NOT DEFINED CMAKE_OBJCXX_ARCHIVE_FINISH) + set(CMAKE_OBJCXX_ARCHIVE_FINISH "<CMAKE_RANLIB> <TARGET>") +endif() + +# compile an Objective-C++ file into an object file +if(NOT CMAKE_OBJCXX_COMPILE_OBJECT) + set(CMAKE_OBJCXX_COMPILE_OBJECT + "<CMAKE_OBJCXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>") +endif() + +if(NOT CMAKE_OBJCXX_LINK_EXECUTABLE) + set(CMAKE_OBJCXX_LINK_EXECUTABLE + "<CMAKE_OBJCXX_COMPILER> <FLAGS> <CMAKE_OBJCXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>") +endif() + +mark_as_advanced( +CMAKE_VERBOSE_MAKEFILE +) + +set(CMAKE_OBJCXX_INFORMATION_LOADED 1) diff --git a/Modules/CMakeTestOBJCCompiler.cmake b/Modules/CMakeTestOBJCCompiler.cmake new file mode 100644 index 0000000..0030683 --- /dev/null +++ b/Modules/CMakeTestOBJCCompiler.cmake @@ -0,0 +1,94 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +if(CMAKE_OBJC_COMPILER_FORCED) + # The compiler configuration was forced by the user. + # Assume the user has configured all compiler information. + set(CMAKE_OBJC_COMPILER_WORKS TRUE) + return() +endif() + +include(CMakeTestCompilerCommon) + +# work around enforced code signing and / or missing exectuable target type +set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) +if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE) + set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE}) +endif() + +# Remove any cached result from an older CMake version. +# We now store this in CMakeCCompiler.cmake. +unset(CMAKE_OBJC_COMPILER_WORKS CACHE) + +# This file is used by EnableLanguage in cmGlobalGenerator to +# determine that that selected Objective-C compiler can actually compile +# and link the most basic of programs. If not, a fatal error +# is set and cmake stops processing commands and will not generate +# any makefiles or projects. +if(NOT CMAKE_OBJC_COMPILER_WORKS) + PrintTestCompilerStatus("OBJC" "") + __TestCompiler_setTryCompileTargetType() + file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCCompiler.m + "#ifdef __cplusplus\n" + "# error \"The CMAKE_OBJC_COMPILER is set to a C++ compiler\"\n" + "#endif\n" + "#ifndef __OBJC__\n" + "# error \"The CMAKE_OBJC_COMPILER is not an Objective-C compiler\"\n" + "#endif\n" + "int main(int argc, char* argv[])\n" + "{ (void)argv; return argc-1;}\n") + try_compile(CMAKE_OBJC_COMPILER_WORKS ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCCompiler.m + OUTPUT_VARIABLE __CMAKE_OBJC_COMPILER_OUTPUT) + # Move result from cache to normal variable. + set(CMAKE_OBJC_COMPILER_WORKS ${CMAKE_OBJC_COMPILER_WORKS}) + unset(CMAKE_OBJC_COMPILER_WORKS CACHE) + set(OBJC_TEST_WAS_RUN 1) + __TestCompiler_restoreTryCompileTargetType() +endif() + +if(NOT CMAKE_OBJC_COMPILER_WORKS) + PrintTestCompilerStatus("OBJC" " -- broken") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the Objective-C compiler works failed with " + "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n") + string(REPLACE "\n" "\n " _output "${__CMAKE_OBJC_COMPILER_OUTPUT}") + message(FATAL_ERROR "The Objective-C compiler\n \"${CMAKE_OBJC_COMPILER}\"\n" + "is not able to compile a simple test program.\nIt fails " + "with the following output:\n ${_output}\n\n" + "CMake will not be able to correctly generate this project.") +else() + if(OBJC_TEST_WAS_RUN) + PrintTestCompilerStatus("OBJC" " -- works") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the Objective-C compiler works passed with " + "the following output:\n${__CMAKE_OBJC_COMPILER_OUTPUT}\n\n") + endif() + + # Try to identify the ABI and configure it into CMakeOBJCCompiler.cmake + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + CMAKE_DETERMINE_COMPILER_ABI(OBJC ${CMAKE_ROOT}/Modules/CMakeOBJCCompilerABI.m) + # Try to identify the compiler features + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake) + CMAKE_DETERMINE_COMPILE_FEATURES(OBJC) + + # Re-configure to save learned information. + configure_file( + ${CMAKE_ROOT}/Modules/CMakeOBJCCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake + @ONLY + ) + include(${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCCompiler.cmake) + + if(CMAKE_OBJC_SIZEOF_DATA_PTR) + foreach(f ${CMAKE_OBJC_ABI_FILES}) + include(${f}) + endforeach() + unset(CMAKE_OBJC_ABI_FILES) + endif() +endif() + +set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE}) +unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE) +unset(__CMAKE_OBJC_COMPILER_OUTPUT) diff --git a/Modules/CMakeTestOBJCXXCompiler.cmake b/Modules/CMakeTestOBJCXXCompiler.cmake new file mode 100644 index 0000000..bcce2f1 --- /dev/null +++ b/Modules/CMakeTestOBJCXXCompiler.cmake @@ -0,0 +1,93 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + + +if(CMAKE_OBJCXX_COMPILER_FORCED) + # The compiler configuration was forced by the user. + # Assume the user has configured all compiler information. + set(CMAKE_OBJCXX_COMPILER_WORKS TRUE) + return() +endif() + +include(CMakeTestCompilerCommon) + +# work around enforced code signing and / or missing exectuable target type +set(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) +if(_CMAKE_FEATURE_DETECTION_TARGET_TYPE) + set(CMAKE_TRY_COMPILE_TARGET_TYPE ${_CMAKE_FEATURE_DETECTION_TARGET_TYPE}) +endif() + +# Remove any cached result from an older CMake version. +# We now store this in CMakeOBJCXXCompiler.cmake. +unset(CMAKE_OBJCXX_COMPILER_WORKS CACHE) + +# This file is used by EnableLanguage in cmGlobalGenerator to +# determine that the selected Objective-C++ compiler can actually compile +# and link the most basic of programs. If not, a fatal error +# is set and cmake stops processing commands and will not generate +# any makefiles or projects. +if(NOT CMAKE_OBJCXX_COMPILER_WORKS) + PrintTestCompilerStatus("OBJCXX" "") + __TestCompiler_setTryCompileTargetType() + file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCXXCompiler.mm + "#ifndef __cplusplus\n" + "# error \"The CMAKE_OBJCXX_COMPILER is set to a C compiler\"\n" + "#endif\n" + "#ifndef __OBJC__\n" + "# error \"The CMAKE_OBJCXX_COMPILER is not an Objective-C++ compiler\"\n" + "#endif\n" + "int main(){return 0;}\n") + try_compile(CMAKE_OBJCXX_COMPILER_WORKS ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/testOBJCXXCompiler.mm + OUTPUT_VARIABLE __CMAKE_OBJCXX_COMPILER_OUTPUT) + # Move result from cache to normal variable. + set(CMAKE_OBJCXX_COMPILER_WORKS ${CMAKE_OBJCXX_COMPILER_WORKS}) + unset(CMAKE_OBJCXX_COMPILER_WORKS CACHE) + set(OBJCXX_TEST_WAS_RUN 1) + __TestCompiler_restoreTryCompileTargetType() +endif() + +if(NOT CMAKE_OBJCXX_COMPILER_WORKS) + PrintTestCompilerStatus("OBJCXX" " -- broken") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Determining if the Objective-C++ compiler works failed with " + "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n") + string(REPLACE "\n" "\n " _output "${__CMAKE_OBJCXX_COMPILER_OUTPUT}") + message(FATAL_ERROR "The Objective-C++ compiler\n \"${CMAKE_OBJCXX_COMPILER}\"\n" + "is not able to compile a simple test program.\nIt fails " + "with the following output:\n ${_output}\n\n" + "CMake will not be able to correctly generate this project.") +else() + if(OBJCXX_TEST_WAS_RUN) + PrintTestCompilerStatus("OBJCXX" " -- works") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Determining if the Objective-C++ compiler works passed with " + "the following output:\n${__CMAKE_OBJCXX_COMPILER_OUTPUT}\n\n") + endif() + + # Try to identify the ABI and configure it into CMakeOBJCXXCompiler.cmake + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompilerABI.cmake) + CMAKE_DETERMINE_COMPILER_ABI(OBJCXX ${CMAKE_ROOT}/Modules/CMakeOBJCXXCompilerABI.mm) + # Try to identify the compiler features + include(${CMAKE_ROOT}/Modules/CMakeDetermineCompileFeatures.cmake) + CMAKE_DETERMINE_COMPILE_FEATURES(OBJCXX) + + # Re-configure to save learned information. + configure_file( + ${CMAKE_ROOT}/Modules/CMakeOBJCXXCompiler.cmake.in + ${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake + @ONLY + ) + include(${CMAKE_PLATFORM_INFO_DIR}/CMakeOBJCXXCompiler.cmake) + + if(CMAKE_OBJCXX_SIZEOF_DATA_PTR) + foreach(f ${CMAKE_OBJCXX_ABI_FILES}) + include(${f}) + endforeach() + unset(CMAKE_OBJCXX_ABI_FILES) + endif() +endif() + +set(CMAKE_TRY_COMPILE_TARGET_TYPE ${__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE}) +unset(__CMAKE_SAVED_TRY_COMPILE_TARGET_TYPE) +unset(__CMAKE_OBJCXX_COMPILER_OUTPUT) diff --git a/Modules/CheckOBJCCompilerFlag.cmake b/Modules/CheckOBJCCompilerFlag.cmake new file mode 100644 index 0000000..1d975da --- /dev/null +++ b/Modules/CheckOBJCCompilerFlag.cmake @@ -0,0 +1,64 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCCompilerFlag +--------------------- + +Check whether the Objective-C compiler supports a given flag. + +.. command:: check_objc_compiler_flag + + .. code-block:: cmake + + check_objc_compiler_flag(<flag> <var>) + + Check that the ``<flag>`` is accepted by the compiler without + a diagnostic. Stores the result in an internal cache entry + named ``<var>``. + +This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable +and calls the ``check_objc_source_compiles`` macro from the +:module:`CheckOBJCSourceCompiles` module. See documentation of that +module for a listing of variables that can otherwise modify the build. + +A positive result from this check indicates only that the compiler did not +issue a diagnostic message when given the flag. Whether the flag has any +effect or even a specific one is beyond the scope of this module. + +.. note:: + Since the :command:`try_compile` command forwards flags from variables + like :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags + in such variables may cause a false negative for this check. +#]=======================================================================] + +include_guard(GLOBAL) +include(CheckOBJCSourceCompiles) +include(CMakeCheckCompilerFlagCommonPatterns) + +macro (CHECK_OBJC_COMPILER_FLAG _FLAG _RESULT) + set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") + + # Normalize locale during test compilation. + set(_CheckOBJCCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) + foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS}) + set(_CheckOBJCCompilerFlag_SAVED_${v} "$ENV{${v}}") + set(ENV{${v}} OBJC) + endforeach() + CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCCompilerFlag_COMMON_PATTERNS) + CHECK_OBJC_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT} + # Some compilers do not fail with a bad flag + FAIL_REGEX "command line option .* is valid for .* but not for Objective-C" # GNU + FAIL_REGEX "argument unused during compilation: .*" # Clang + ${_CheckOBJCCompilerFlag_COMMON_PATTERNS} + ) + foreach(v ${_CheckOBJCCompilerFlag_LOCALE_VARS}) + set(ENV{${v}} ${_CheckOBJCCompilerFlag_SAVED_${v}}) + unset(_CheckOBJCCompilerFlag_SAVED_${v}) + endforeach() + unset(_CheckOBJCCompilerFlag_LOCALE_VARS) + unset(_CheckOBJCCompilerFlag_COMMON_PATTERNS) + + set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") +endmacro () diff --git a/Modules/CheckOBJCSourceCompiles.cmake b/Modules/CheckOBJCSourceCompiles.cmake new file mode 100644 index 0000000..a4676ad --- /dev/null +++ b/Modules/CheckOBJCSourceCompiles.cmake @@ -0,0 +1,145 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCSourceCompiles +----------------------- + +Check if given Objective-C source compiles and links into an executable. + +.. command:: check_objc_source_compiles + + .. code-block:: cmake + + check_objc_source_compiles(<code> <resultVar> + [FAIL_REGEX <regex1> [<regex2>...]]) + + Check that the source supplied in ``<code>`` can be compiled as a Objectie-C source + file and linked as an executable (so it must contain at least a ``main()`` + function). The result will be stored in the internal cache variable specified + by ``<resultVar>``, with a boolean true value for success and boolean false + for failure. If ``FAIL_REGEX`` is provided, then failure is determined by + checking if anything in the output matches any of the specified regular + expressions. + + The underlying check is performed by the :command:`try_compile` command. The + compile and link commands can be influenced by setting any of the following + variables prior to calling ``check_objc_source_compiles()``: + + ``CMAKE_REQUIRED_FLAGS`` + Additional flags to pass to the compiler. Note that the contents of + :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated + configuration-specific variable are automatically added to the compiler + command before the contents of ``CMAKE_REQUIRED_FLAGS``. + + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ``<resultVar>`` will also be added automatically. + + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list <CMake Language Lists>` of header search paths to pass to + the compiler. These will be the only header search paths used by + ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` + directory property will be ignored. + + ``CMAKE_REQUIRED_LINK_OPTIONS`` + A :ref:`;-list <CMake Language Lists>` of options to add to the link + command (see :command:`try_compile` for further details). + + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list <CMake Language Lists>` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for + further details). + + ``CMAKE_REQUIRED_QUIET`` + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. + + The check is only performed once, with the result cached in the variable + named by ``<resultVar>``. Every subsequent CMake run will re-use this cached + value rather than performing the check again, even if the ``<code>`` changes. + In order to force the check to be re-evaluated, the variable named by + ``<resultVar>`` must be manually removed from the cache. + +#]=======================================================================] + +include_guard(GLOBAL) + +macro(CHECK_OBJC_SOURCE_COMPILES SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(_FAIL_REGEX) + set(_key) + foreach(arg ${ARGN}) + if("${arg}" MATCHES "^(FAIL_REGEX)$") + set(_key "${arg}") + elseif(_key) + list(APPEND _${_key} "${arg}") + else() + message(FATAL_ERROR "Unknown argument:\n ${arg}\n") + endif() + endforeach() + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LINK_OPTIONS) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS) + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_compile(${VAR} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS} + ${CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + + foreach(_regex ${_FAIL_REGEX}) + if("${OUTPUT}" MATCHES "${_regex}") + set(${VAR} 0) + endif() + endforeach() + + if(${VAR}) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Objective-C SOURCE FILE Test ${VAR} succeeded with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Objective-C SOURCE FILE Test ${VAR} failed with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + endif() + endif() +endmacro() diff --git a/Modules/CheckOBJCSourceRuns.cmake b/Modules/CheckOBJCSourceRuns.cmake new file mode 100644 index 0000000..00a1ebd --- /dev/null +++ b/Modules/CheckOBJCSourceRuns.cmake @@ -0,0 +1,145 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCSourceRuns +------------------- + +Check if given Objective-C source compiles and links into an executable and can +subsequently be run. + +.. command:: check_objc_source_runs + + .. code-block:: cmake + + check_objc_source_runs(<code> <resultVar>) + + Check that the source supplied in ``<code>`` can be compiled as a Objective-C source + file, linked as an executable and then run. The ``<code>`` must contain at + least a ``main()`` function. If the ``<code>`` could be built and run + successfully, the internal cache variable specified by ``<resultVar>`` will + be set to 1, otherwise it will be set to an value that evaluates to boolean + false (e.g. an empty string or an error message). + + The underlying check is performed by the :command:`try_run` command. The + compile and link commands can be influenced by setting any of the following + variables prior to calling ``check_objc_source_runs()``: + + ``CMAKE_REQUIRED_FLAGS`` + Additional flags to pass to the compiler. Note that the contents of + :variable:`CMAKE_OBJC_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated + configuration-specific variable are automatically added to the compiler + command before the contents of ``CMAKE_REQUIRED_FLAGS``. + + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ``<resultVar>`` will also be added automatically. + + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list <CMake Language Lists>` of header search paths to pass to + the compiler. These will be the only header search paths used by + ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` + directory property will be ignored. + + ``CMAKE_REQUIRED_LINK_OPTIONS`` + A :ref:`;-list <CMake Language Lists>` of options to add to the link + command (see :command:`try_run` for further details). + + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list <CMake Language Lists>` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for + further details). + + ``CMAKE_REQUIRED_QUIET`` + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. + + The check is only performed once, with the result cached in the variable + named by ``<resultVar>``. Every subsequent CMake run will re-use this cached + value rather than performing the check again, even if the ``<code>`` changes. + In order to force the check to be re-evaluated, the variable named by + ``<resultVar>`` must be manually removed from the cache. + +#]=======================================================================] + +include_guard(GLOBAL) + +macro(CHECK_OBJC_SOURCE_RUNS SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LINK_OPTIONS) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS) + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_run(${VAR}_EXITCODE ${VAR}_COMPILED + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.m + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_OBJC_SOURCE_COMPILES_ADD_LINK_OPTIONS} + ${CHECK_OBJC_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} + "${CHECK_OBJC_SOURCE_COMPILES_ADD_INCLUDES}" + COMPILE_OUTPUT_VARIABLE OUTPUT + RUN_OUTPUT_VARIABLE RUN_OUTPUT) + # if it did not compile make the return value fail code of 1 + if(NOT ${VAR}_COMPILED) + set(${VAR}_EXITCODE 1) + endif() + # if the return value was 0 then it worked + if("${${VAR}_EXITCODE}" EQUAL 0) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Objective-C SOURCE FILE Test ${VAR} succeeded with the following compile output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${VAR}}\n" + "Source file was:\n${SOURCE}\n") + else() + if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") + set(${VAR} "${${VAR}_EXITCODE}") + else() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + endif() + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Objective-C SOURCE FILE Test ${VAR} failed with the following compile output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${VAR}_EXITCODE}\n" + "Source file was:\n${SOURCE}\n") + + endif() + endif() +endmacro() diff --git a/Modules/CheckOBJCXXCompilerFlag.cmake b/Modules/CheckOBJCXXCompilerFlag.cmake new file mode 100644 index 0000000..c32741b --- /dev/null +++ b/Modules/CheckOBJCXXCompilerFlag.cmake @@ -0,0 +1,64 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCXXCompilerFlag +----------------------- + +Check whether the Objective-C++ compiler supports a given flag. + +.. command:: check_objcxx_compiler_flag + + .. code-block:: cmake + + check_objcxx_compiler_flag(<flag> <var>) + + Check that the ``<flag>`` is accepted by the compiler without + a diagnostic. Stores the result in an internal cache entry + named ``<var>``. + +This command temporarily sets the ``CMAKE_REQUIRED_DEFINITIONS`` variable +and calls the ``check_objcxx_source_compiles`` macro from the +:module:`CheckOBJCXXSourceCompiles` module. See documentation of that +module for a listing of variables that can otherwise modify the build. + +A positive result from this check indicates only that the compiler did not +issue a diagnostic message when given the flag. Whether the flag has any +effect or even a specific one is beyond the scope of this module. + +.. note:: + Since the :command:`try_compile` command forwards flags from variables + like :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>`, unknown flags + in such variables may cause a false negative for this check. +#]=======================================================================] + +include_guard(GLOBAL) +include(CheckOBJCXXSourceCompiles) +include(CMakeCheckCompilerFlagCommonPatterns) + +macro (CHECK_OBJCXX_COMPILER_FLAG _FLAG _RESULT) + set(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + set(CMAKE_REQUIRED_DEFINITIONS "${_FLAG}") + + # Normalize locale during test compilation. + set(_CheckOBJCXXCompilerFlag_LOCALE_VARS LC_ALL LC_MESSAGES LANG) + foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS}) + set(_CheckOBJCXXCompilerFlag_SAVED_${v} "$ENV{${v}}") + set(ENV{${v}} OBJCXX) + endforeach() + CHECK_COMPILER_FLAG_COMMON_PATTERNS(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS) + CHECK_OBJCXX_SOURCE_COMPILES("#ifndef __OBJC__\n# error \"Not an Objective-C++ compiler\"\n#endif\nint main(void) { return 0; }" ${_RESULT} + # Some compilers do not fail with a bad flag + FAIL_REGEX "command line option .* is valid for .* but not for Objective-C\\\\+\\\\+" # GNU + FAIL_REGEX "argument unused during compilation: .*" # Clang + ${_CheckOBJCXXCompilerFlag_COMMON_PATTERNS} + ) + foreach(v ${_CheckOBJCXXCompilerFlag_LOCALE_VARS}) + set(ENV{${v}} ${_CheckOBJCXXCompilerFlag_SAVED_${v}}) + unset(_CheckOBJCXXCompilerFlag_SAVED_${v}) + endforeach() + unset(_CheckOBJCXXCompilerFlag_LOCALE_VARS) + unset(_CheckOBJCXXCompilerFlag_COMMON_PATTERNS) + + set (CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") +endmacro () diff --git a/Modules/CheckOBJCXXSourceCompiles.cmake b/Modules/CheckOBJCXXSourceCompiles.cmake new file mode 100644 index 0000000..4c0fdd0 --- /dev/null +++ b/Modules/CheckOBJCXXSourceCompiles.cmake @@ -0,0 +1,146 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCXXSourceCompiles +------------------------- + +Check if given Objective-C++ source compiles and links into an executable. + +.. command:: check_objcxx_source_compiles + + .. code-block:: cmake + + check_objcxx_source_compiles(<code> <resultVar> + [FAIL_REGEX <regex1> [<regex2>...]]) + + Check that the source supplied in ``<code>`` can be compiled as a Objective-C++ source + file and linked as an executable (so it must contain at least a ``main()`` + function). The result will be stored in the internal cache variable specified + by ``<resultVar>``, with a boolean true value for success and boolean false + for failure. If ``FAIL_REGEX`` is provided, then failure is determined by + checking if anything in the output matches any of the specified regular + expressions. + + The underlying check is performed by the :command:`try_compile` command. The + compile and link commands can be influenced by setting any of the following + variables prior to calling ``check_objcxx_source_compiles()``: + + ``CMAKE_REQUIRED_FLAGS`` + Additional flags to pass to the compiler. Note that the contents of + :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated + configuration-specific variable are automatically added to the compiler + command before the contents of ``CMAKE_REQUIRED_FLAGS``. + + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ``<resultVar>`` will also be added automatically. + + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list <CMake Language Lists>` of header search paths to pass to + the compiler. These will be the only header search paths used by + ``try_compile()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` + directory property will be ignored. + + ``CMAKE_REQUIRED_LINK_OPTIONS`` + A :ref:`;-list <CMake Language Lists>` of options to add to the link + command (see :command:`try_compile` for further details). + + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list <CMake Language Lists>` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets <Imported Targets>` (see :command:`try_compile` for + further details). + + ``CMAKE_REQUIRED_QUIET`` + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. + + The check is only performed once, with the result cached in the variable + named by ``<resultVar>``. Every subsequent CMake run will re-use this cached + value rather than performing the check again, even if the ``<code>`` changes. + In order to force the check to be re-evaluated, the variable named by + ``<resultVar>`` must be manually removed from the cache. + +#]=======================================================================] + +include_guard(GLOBAL) + +macro(CHECK_OBJCXX_SOURCE_COMPILES SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(_FAIL_REGEX) + set(_key) + foreach(arg ${ARGN}) + if("${arg}" MATCHES "^(FAIL_REGEX)$") + set(_key "${arg}") + elseif(_key) + list(APPEND _${_key} "${arg}") + else() + message(FATAL_ERROR "Unknown argument:\n ${arg}\n") + endif() + endforeach() + + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LINK_OPTIONS) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS) + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_compile(${VAR} + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS} + ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES}" + OUTPUT_VARIABLE OUTPUT) + + foreach(_regex ${_FAIL_REGEX}) + if("${OUTPUT}" MATCHES "${_regex}") + set(${VAR} 0) + endif() + endforeach() + + if(${VAR}) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Objective-C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + else() + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Objective-C++ SOURCE FILE Test ${VAR} failed with the following output:\n" + "${OUTPUT}\n" + "Source file was:\n${SOURCE}\n") + endif() + endif() +endmacro() diff --git a/Modules/CheckOBJCXXSourceRuns.cmake b/Modules/CheckOBJCXXSourceRuns.cmake new file mode 100644 index 0000000..a3d5923 --- /dev/null +++ b/Modules/CheckOBJCXXSourceRuns.cmake @@ -0,0 +1,145 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +CheckOBJCXXSourceRuns +--------------------- + +Check if given Objective-C++ source compiles and links into an executable and can +subsequently be run. + +.. command:: check_objcxx_source_runs + + .. code-block:: cmake + + check_objcxx_source_runs(<code> <resultVar>) + + Check that the source supplied in ``<code>`` can be compiled as a Objective-C++ source + file, linked as an executable and then run. The ``<code>`` must contain at + least a ``main()`` function. If the ``<code>`` could be built and run + successfully, the internal cache variable specified by ``<resultVar>`` will + be set to 1, otherwise it will be set to an value that evaluates to boolean + false (e.g. an empty string or an error message). + + The underlying check is performed by the :command:`try_run` command. The + compile and link commands can be influenced by setting any of the following + variables prior to calling ``check_objcxx_source_runs()``: + + ``CMAKE_REQUIRED_FLAGS`` + Additional flags to pass to the compiler. Note that the contents of + :variable:`CMAKE_OBJCXX_FLAGS <CMAKE_<LANG>_FLAGS>` and its associated + configuration-specific variable are automatically added to the compiler + command before the contents of ``CMAKE_REQUIRED_FLAGS``. + + ``CMAKE_REQUIRED_DEFINITIONS`` + A :ref:`;-list <CMake Language Lists>` of compiler definitions of the form + ``-DFOO`` or ``-DFOO=bar``. A definition for the name specified by + ``<resultVar>`` will also be added automatically. + + ``CMAKE_REQUIRED_INCLUDES`` + A :ref:`;-list <CMake Language Lists>` of header search paths to pass to + the compiler. These will be the only header search paths used by + ``try_run()``, i.e. the contents of the :prop_dir:`INCLUDE_DIRECTORIES` + directory property will be ignored. + + ``CMAKE_REQUIRED_LINK_OPTIONS`` + A :ref:`;-list <CMake Language Lists>` of options to add to the link + command (see :command:`try_run` for further details). + + ``CMAKE_REQUIRED_LIBRARIES`` + A :ref:`;-list <CMake Language Lists>` of libraries to add to the link + command. These can be the name of system libraries or they can be + :ref:`Imported Targets <Imported Targets>` (see :command:`try_run` for + further details). + + ``CMAKE_REQUIRED_QUIET`` + If this variable evaluates to a boolean true value, all status messages + associated with the check will be suppressed. + + The check is only performed once, with the result cached in the variable + named by ``<resultVar>``. Every subsequent CMake run will re-use this cached + value rather than performing the check again, even if the ``<code>`` changes. + In order to force the check to be re-evaluated, the variable named by + ``<resultVar>`` must be manually removed from the cache. + +#]=======================================================================] + +include_guard(GLOBAL) + +macro(CHECK_OBJCXX_SOURCE_RUNS SOURCE VAR) + if(NOT DEFINED "${VAR}") + set(MACRO_CHECK_FUNCTION_DEFINITIONS + "-D${VAR} ${CMAKE_REQUIRED_FLAGS}") + if(CMAKE_REQUIRED_LINK_OPTIONS) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS + LINK_OPTIONS ${CMAKE_REQUIRED_LINK_OPTIONS}) + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS) + endif() + if(CMAKE_REQUIRED_LIBRARIES) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES + LINK_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES) + endif() + if(CMAKE_REQUIRED_INCLUDES) + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES + "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}") + else() + set(CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES) + endif() + file(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm" + "${SOURCE}\n") + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR}") + endif() + try_run(${VAR}_EXITCODE ${VAR}_COMPILED + ${CMAKE_BINARY_DIR} + ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.mm + COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} + ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LINK_OPTIONS} + ${CHECK_OBJCXX_SOURCE_COMPILES_ADD_LIBRARIES} + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + -DCMAKE_SKIP_RPATH:BOOL=${CMAKE_SKIP_RPATH} + "${CHECK_OBJCXX_SOURCE_COMPILES_ADD_INCLUDES}" + COMPILE_OUTPUT_VARIABLE OUTPUT + RUN_OUTPUT_VARIABLE RUN_OUTPUT) + + # if it did not compile make the return value fail code of 1 + if(NOT ${VAR}_COMPILED) + set(${VAR}_EXITCODE 1) + endif() + # if the return value was 0 then it worked + if("${${VAR}_EXITCODE}" EQUAL 0) + set(${VAR} 1 CACHE INTERNAL "Test ${VAR}") + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Success") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log + "Performing Objective-C++ SOURCE FILE Test ${VAR} succeeded with the following output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${VAR}}\n" + "Source file was:\n${SOURCE}\n") + else() + if(CMAKE_CROSSCOMPILING AND "${${VAR}_EXITCODE}" MATCHES "FAILED_TO_RUN") + set(${VAR} "${${VAR}_EXITCODE}") + else() + set(${VAR} "" CACHE INTERNAL "Test ${VAR}") + endif() + + if(NOT CMAKE_REQUIRED_QUIET) + message(STATUS "Performing Test ${VAR} - Failed") + endif() + file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log + "Performing Objective-C++ SOURCE FILE Test ${VAR} failed with the following output:\n" + "${OUTPUT}\n" + "...and run output:\n" + "${RUN_OUTPUT}\n" + "Return value: ${${VAR}_EXITCODE}\n" + "Source file was:\n${SOURCE}\n") + endif() + endif() +endmacro() diff --git a/Modules/Compiler/AppleClang-OBJC.cmake b/Modules/Compiler/AppleClang-OBJC.cmake new file mode 100644 index 0000000..d1f3706 --- /dev/null +++ b/Modules/Compiler/AppleClang-OBJC.cmake @@ -0,0 +1,17 @@ +include(Compiler/Clang-OBJC) + +if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.0) + set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90") + set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90") + set(CMAKE_OBJC90_STANDARD__HAS_FULL_SUPPORT ON) + + set(CMAKE_OBJC99_STANDARD_COMPILE_OPTION "-std=c99") + set(CMAKE_OBJC99_EXTENSION_COMPILE_OPTION "-std=gnu99") + set(CMAKE_OBJC99_STANDARD__HAS_FULL_SUPPORT ON) + + set(CMAKE_OBJC11_STANDARD_COMPILE_OPTION "-std=c11") + set(CMAKE_OBJC11_EXTENSION_COMPILE_OPTION "-std=gnu11") + set(CMAKE_OBJC11_STANDARD__HAS_FULL_SUPPORT ON) +endif() + +__compiler_check_default_language_standard(OBJC 4.0 99) diff --git a/Modules/Compiler/AppleClang-OBJCXX.cmake b/Modules/Compiler/AppleClang-OBJCXX.cmake new file mode 100644 index 0000000..7c6f763 --- /dev/null +++ b/Modules/Compiler/AppleClang-OBJCXX.cmake @@ -0,0 +1,37 @@ +include(Compiler/Clang-OBJCXX) + +if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.0) + set(CMAKE_OBJCXX98_STANDARD_COMPILE_OPTION "-std=c++98") + set(CMAKE_OBJCXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98") + set(CMAKE_OBJCXX98_STANDARD__HAS_FULL_SUPPORT ON) + + set(CMAKE_OBJCXX11_STANDARD_COMPILE_OPTION "-std=c++11") + set(CMAKE_OBJCXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") +endif() + +if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1) + set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++14") + set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") + set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON) +elseif(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 5.1) + # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro greater than 201103L + set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++1y") + set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") + set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON) +endif() + +if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 6.1) + set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++1z") + set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") +endif() + +if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 8.0) + set(CMAKE_OBJCXX11_STANDARD__HAS_FULL_SUPPORT ON) +endif() + +if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 10.0) + set(CMAKE_OBJCXX20_STANDARD_COMPILE_OPTION "-std=c++2a") + set(CMAKE_OBJCXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a") +endif() + +__compiler_check_default_language_standard(OBJCXX 4.0 98) diff --git a/Modules/Compiler/Clang-OBJC.cmake b/Modules/Compiler/Clang-OBJC.cmake new file mode 100644 index 0000000..c61c497 --- /dev/null +++ b/Modules/Compiler/Clang-OBJC.cmake @@ -0,0 +1,18 @@ +include(Compiler/Clang) +__compiler_clang(OBJC) + +if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 3.4) + set(CMAKE_OBJC90_STANDARD_COMPILE_OPTION "-std=c90") + set(CMAKE_OBJC90_EXTENSION_COMPILE_OPTION "-std=gnu90") + set(CMAKE_OBJC90_STANDARD__HAS_FULL_SUPPORT ON) + + set(CMAKE_OBJC99_STANDARD_COMPILE_OPTION "-std=c99") + set(CMAKE_OBJC99_EXTENSION_COMPILE_OPTION "-std=gnu99") + set(CMAKE_OBJC99_STANDARD__HAS_FULL_SUPPORT ON) + + set(CMAKE_OBJC11_STANDARD_COMPILE_OPTION "-std=c11") + set(CMAKE_OBJC11_EXTENSION_COMPILE_OPTION "-std=gnu11") + set(CMAKE_OBJC11_STANDARD__HAS_FULL_SUPPORT ON) +endif() + +__compiler_check_default_language_standard(OBJC 3.4 99 3.6 11) diff --git a/Modules/Compiler/Clang-OBJCXX.cmake b/Modules/Compiler/Clang-OBJCXX.cmake new file mode 100644 index 0000000..b01ce64 --- /dev/null +++ b/Modules/Compiler/Clang-OBJCXX.cmake @@ -0,0 +1,70 @@ +include(Compiler/Clang) +__compiler_clang(OBJCXX) + +if("x${CMAKE_OBJCXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xGNU") + if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 2.1) + set(CMAKE_OBJCXX98_STANDARD_COMPILE_OPTION "-std=c++98") + set(CMAKE_OBJCXX98_EXTENSION_COMPILE_OPTION "-std=gnu++98") + endif() + + if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 3.1) + set(CMAKE_OBJCXX98_STANDARD__HAS_FULL_SUPPORT ON) + set(CMAKE_OBJCXX11_STANDARD_COMPILE_OPTION "-std=c++11") + set(CMAKE_OBJCXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") + set(CMAKE_OBJCXX11_STANDARD__HAS_FULL_SUPPORT ON) + elseif(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 2.1) + set(CMAKE_OBJCXX11_STANDARD_COMPILE_OPTION "-std=c++0x") + set(CMAKE_OBJCXX11_EXTENSION_COMPILE_OPTION "-std=gnu++0x") + endif() + + if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 3.5) + set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++14") + set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") + set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON) + elseif(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 3.4) + set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std=c++1y") + set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") + set(CMAKE_OBJCXX14_STANDARD__HAS_FULL_SUPPORT ON) + endif() + + set(_clang_version_std17 5.0) + + if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS "${_clang_version_std17}") + set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++17") + set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++17") + elseif (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 3.5) + set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std=c++1z") + set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std=gnu++1z") + endif() + + if (NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS "${_clang_version_std17}") + set(CMAKE_OBJCXX20_STANDARD_COMPILE_OPTION "-std=c++2a") + set(CMAKE_OBJCXX20_EXTENSION_COMPILE_OPTION "-std=gnu++2a") + endif() + + unset(_clang_version_std17) + + __compiler_check_default_language_standard(OBJCXX 2.1 98) +elseif(CMAKE_OBJCXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.9 + AND CMAKE_OBJCXX_SIMULATE_VERSION VERSION_GREATER_EQUAL 19.0) + # This version of clang-cl and the MSVC version it simulates have + # support for -std: flags. + set(CMAKE_OBJCXX98_STANDARD_COMPILE_OPTION "") + set(CMAKE_OBJCXX98_EXTENSION_COMPILE_OPTION "") + set(CMAKE_OBJCXX98_STANDARD__HAS_FULL_SUPPORT ON) + set(CMAKE_OBJCXX11_STANDARD_COMPILE_OPTION "") + set(CMAKE_OBJCXX11_EXTENSION_COMPILE_OPTION "") + set(CMAKE_OBJCXX14_STANDARD_COMPILE_OPTION "-std:c++14") + set(CMAKE_OBJCXX14_EXTENSION_COMPILE_OPTION "-std:c++14") + if (CMAKE_OBJCXX_COMPILER_VERSION VERSION_GREATER_EQUAL 6.0) + set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std:c++17") + set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std:c++17") + set(CMAKE_OBJCXX20_STANDARD_COMPILE_OPTION "-std:c++latest") + set(CMAKE_OBJCXX20_EXTENSION_COMPILE_OPTION "-std:c++latest") + else() + set(CMAKE_OBJCXX17_STANDARD_COMPILE_OPTION "-std:c++latest") + set(CMAKE_OBJCXX17_EXTENSION_COMPILE_OPTION "-std:c++latest") + endif() + + __compiler_check_default_language_standard(OBJCXX 3.9 14) +endif() diff --git a/Modules/Compiler/GNU-OBJC.cmake b/Modules/Compiler/GNU-OBJC.cmake new file mode 100644 index 0000000..5fba801 --- /dev/null +++ b/Modules/Compiler/GNU-OBJC.cmake @@ -0,0 +1,6 @@ +include(Compiler/GNU) +__compiler_gnu(OBJC) + +if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2) + set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden") +endif() diff --git a/Modules/Compiler/GNU-OBJCXX.cmake b/Modules/Compiler/GNU-OBJCXX.cmake new file mode 100644 index 0000000..66a547e --- /dev/null +++ b/Modules/Compiler/GNU-OBJCXX.cmake @@ -0,0 +1,10 @@ +include(Compiler/GNU) +__compiler_gnu(OBJC) + +if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.2) + set(CMAKE_CXX_COMPILE_OPTIONS_VISIBILITY_INLINES_HIDDEN "-fvisibility-inlines-hidden") +endif() + +if(NOT CMAKE_OBJCXX_LINK_FLAGS) + set(CMAKE_OBCXX_LINK_FLAGS "-lstdc++") +endif() diff --git a/Modules/FindPackageHandleStandardArgs.cmake b/Modules/FindPackageHandleStandardArgs.cmake index a2999fc..d824ee8 100644 --- a/Modules/FindPackageHandleStandardArgs.cmake +++ b/Modules/FindPackageHandleStandardArgs.cmake @@ -27,6 +27,7 @@ valid filepaths. [VERSION_VAR <version-var>] [HANDLE_COMPONENTS] [CONFIG_MODE] + [REASON_FAILURE_MESSAGE <reason-failure-message>] [FAIL_MESSAGE <custom-failure-message>] ) @@ -81,6 +82,10 @@ valid filepaths. will automatically check whether the package configuration file was found. + ``REASON_FAILURE_MESSAGE <reason-failure-message>`` + Specify a custom message of the reason for the failure which will be + appended to the default generated message. + ``FAIL_MESSAGE <custom-failure-message>`` Specify a custom failure message instead of using the default generated message. Not recommended. @@ -133,11 +138,15 @@ include(${CMAKE_CURRENT_LIST_DIR}/FindPackageMessage.cmake) # internal helper macro macro(_FPHSA_FAILURE_MESSAGE _msg) + set (__msg "${_msg}") + if (FPHSA_REASON_FAILURE_MESSAGE) + string(APPEND __msg "\n Reason given by package: ${FPHSA_REASON_FAILURE_MESSAGE}\n") + endif() if (${_NAME}_FIND_REQUIRED) - message(FATAL_ERROR "${_msg}") + message(FATAL_ERROR "${__msg}") else () if (NOT ${_NAME}_FIND_QUIETLY) - message(STATUS "${_msg}") + message(STATUS "${__msg}") endif () endif () endmacro() @@ -158,12 +167,18 @@ macro(_FPHSA_HANDLE_FAILURE_CONFIG_MODE) foreach(currentConfigIndex RANGE ${configsCount}) list(GET ${_NAME}_CONSIDERED_CONFIGS ${currentConfigIndex} filename) list(GET ${_NAME}_CONSIDERED_VERSIONS ${currentConfigIndex} version) - string(APPEND configsText " ${filename} (version ${version})\n") + string(APPEND configsText "\n ${filename} (version ${version})") endforeach() if (${_NAME}_NOT_FOUND_MESSAGE) - string(APPEND configsText " Reason given by package: ${${_NAME}_NOT_FOUND_MESSAGE}\n") + if (FPHSA_REASON_FAILURE_MESSAGE) + string(PREPEND FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}\n ") + else() + set(FPHSA_REASON_FAILURE_MESSAGE "${${_NAME}_NOT_FOUND_MESSAGE}") + endif() + else() + string(APPEND configsText "\n") endif() - _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:\n${configsText}") + _FPHSA_FAILURE_MESSAGE("${FPHSA_FAIL_MESSAGE} ${VERSION_MSG}, checked the following files:${configsText}") else() # Simple case: No Config-file was found at all: @@ -177,7 +192,7 @@ function(FIND_PACKAGE_HANDLE_STANDARD_ARGS _NAME _FIRST_ARG) # Set up the arguments for `cmake_parse_arguments`. set(options CONFIG_MODE HANDLE_COMPONENTS) - set(oneValueArgs FAIL_MESSAGE VERSION_VAR FOUND_VAR) + set(oneValueArgs FAIL_MESSAGE REASON_FAILURE_MESSAGE VERSION_VAR FOUND_VAR) set(multiValueArgs REQUIRED_VARS) # Check whether we are in 'simple' or 'extended' mode: diff --git a/Modules/Platform/Apple-AppleClang-OBJC.cmake b/Modules/Platform/Apple-AppleClang-OBJC.cmake new file mode 100644 index 0000000..b78edb1 --- /dev/null +++ b/Modules/Platform/Apple-AppleClang-OBJC.cmake @@ -0,0 +1,6 @@ +include(Platform/Apple-Clang-OBJC) +if(NOT CMAKE_OBJC_COMPILER_VERSION VERSION_LESS 4.2) + set(CMAKE_OBJC_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ") +else() + unset(CMAKE_OBJC_SYSTEM_FRAMEWORK_SEARCH_FLAG) +endif() diff --git a/Modules/Platform/Apple-AppleClang-OBJCXX.cmake b/Modules/Platform/Apple-AppleClang-OBJCXX.cmake new file mode 100644 index 0000000..ed172f1 --- /dev/null +++ b/Modules/Platform/Apple-AppleClang-OBJCXX.cmake @@ -0,0 +1,6 @@ +include(Platform/Apple-Clang-OBJCXX) +if(NOT CMAKE_OBJCXX_COMPILER_VERSION VERSION_LESS 4.2) + set(CMAKE_OBJCXX_SYSTEM_FRAMEWORK_SEARCH_FLAG "-iframework ") +else() + unset(CMAKE_OBJCXX_SYSTEM_FRAMEWORK_SEARCH_FLAG) +endif() diff --git a/Modules/Platform/Apple-Clang-OBJC.cmake b/Modules/Platform/Apple-Clang-OBJC.cmake new file mode 100644 index 0000000..63cd846 --- /dev/null +++ b/Modules/Platform/Apple-Clang-OBJC.cmake @@ -0,0 +1,2 @@ +include(Platform/Apple-Clang) +__apple_compiler_clang(OBJC) diff --git a/Modules/Platform/Apple-Clang-OBJCXX.cmake b/Modules/Platform/Apple-Clang-OBJCXX.cmake new file mode 100644 index 0000000..28fc352 --- /dev/null +++ b/Modules/Platform/Apple-Clang-OBJCXX.cmake @@ -0,0 +1,2 @@ +include(Platform/Apple-Clang) +__apple_compiler_clang(OBJCXX) diff --git a/Modules/Platform/Apple-GNU-OBJC.cmake b/Modules/Platform/Apple-GNU-OBJC.cmake new file mode 100644 index 0000000..aa8b33f --- /dev/null +++ b/Modules/Platform/Apple-GNU-OBJC.cmake @@ -0,0 +1,4 @@ +include(Platform/Apple-GNU) +__apple_compiler_gnu(OBJC) +cmake_gnu_set_sysroot_flag(OBJC) +cmake_gnu_set_osx_deployment_target_flag(OBJC) diff --git a/Modules/Platform/Apple-GNU-OBJCXX.cmake b/Modules/Platform/Apple-GNU-OBJCXX.cmake new file mode 100644 index 0000000..919e11d --- /dev/null +++ b/Modules/Platform/Apple-GNU-OBJCXX.cmake @@ -0,0 +1,4 @@ +include(Platform/Apple-GNU) +__apple_compiler_gnu(OBJCXX) +cmake_gnu_set_sysroot_flag(OBJCXX) +cmake_gnu_set_osx_deployment_target_flag(OBJCXX) diff --git a/Modules/Platform/Darwin.cmake b/Modules/Platform/Darwin.cmake index 7e02814..d0bb359 100644 --- a/Modules/Platform/Darwin.cmake +++ b/Modules/Platform/Darwin.cmake @@ -119,10 +119,18 @@ set(CMAKE_C_CREATE_MACOSX_FRAMEWORK set(CMAKE_CXX_CREATE_MACOSX_FRAMEWORK "<CMAKE_CXX_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_CXX_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>") +set(CMAKE_OBJC_CREATE_MACOSX_FRAMEWORK + "<CMAKE_OBJC_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJC_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>") + +set(CMAKE_OBJCXX_CREATE_MACOSX_FRAMEWORK + "<CMAKE_OBJCXX_COMPILER> <LANGUAGE_COMPILE_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_OBJCXX_FLAGS> <LINK_FLAGS> -o <TARGET> <SONAME_FLAG> <TARGET_INSTALLNAME_DIR><TARGET_SONAME> <OBJECTS> <LINK_LIBRARIES>") + # Set default framework search path flag for languages known to use a # preprocessor that may find headers in frameworks. set(CMAKE_C_FRAMEWORK_SEARCH_FLAG -F) set(CMAKE_CXX_FRAMEWORK_SEARCH_FLAG -F) +set(CMAKE_OBJC_FRAMEWORK_SEARCH_FLAG -F) +set(CMAKE_OBJCXX_FRAMEWORK_SEARCH_FLAG -F) set(CMAKE_Fortran_FRAMEWORK_SEARCH_FLAG -F) # default to searching for frameworks first @@ -222,7 +230,7 @@ unset(_apps_paths) include(Platform/UnixPaths) if(_CMAKE_OSX_SYSROOT_PATH AND EXISTS ${_CMAKE_OSX_SYSROOT_PATH}/usr/include) list(APPEND CMAKE_SYSTEM_PREFIX_PATH ${_CMAKE_OSX_SYSROOT_PATH}/usr) - foreach(lang C CXX) + foreach(lang C CXX OBJC OBJCXX) list(APPEND _CMAKE_${lang}_IMPLICIT_INCLUDE_DIRECTORIES_INIT ${_CMAKE_OSX_SYSROOT_PATH}/usr/include) endforeach() endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 0c1f3b1..4e3e842 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1145,7 +1145,7 @@ target_link_libraries(cpack CPackLib) # Curses GUI if(BUILD_CursesDialog) - include(${CMake_SOURCE_DIR}/Source/CursesDialog/CMakeLists.txt) + add_subdirectory(CursesDialog) endif() # Qt GUI diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index d9ca09b..2196243 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 15) -set(CMake_VERSION_PATCH 20190927) +set(CMake_VERSION_PATCH 20190930) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CursesDialog/CMakeLists.txt b/Source/CursesDialog/CMakeLists.txt index 270b07e..7009717 100644 --- a/Source/CursesDialog/CMakeLists.txt +++ b/Source/CursesDialog/CMakeLists.txt @@ -1,26 +1,22 @@ # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. -set( CURSES_SRCS - CursesDialog/cmCursesOptionsWidget.cxx - CursesDialog/cmCursesBoolWidget.cxx - CursesDialog/cmCursesCacheEntryComposite.cxx - CursesDialog/cmCursesDummyWidget.cxx - CursesDialog/cmCursesFilePathWidget.cxx - CursesDialog/cmCursesForm.cxx - CursesDialog/cmCursesLabelWidget.cxx - CursesDialog/cmCursesLongMessageForm.cxx - CursesDialog/cmCursesMainForm.cxx - CursesDialog/cmCursesPathWidget.cxx - CursesDialog/cmCursesStringWidget.cxx - CursesDialog/cmCursesWidget.cxx - CursesDialog/ccmake.cxx - ) - -include_directories(${CURSES_INCLUDE_PATH}) - - -add_executable(ccmake ${CURSES_SRCS} ) +add_executable(ccmake + ccmake.cxx + cmCursesBoolWidget.cxx + cmCursesCacheEntryComposite.cxx + cmCursesDummyWidget.cxx + cmCursesFilePathWidget.cxx + cmCursesForm.cxx + cmCursesLabelWidget.cxx + cmCursesLongMessageForm.cxx + cmCursesMainForm.cxx + cmCursesOptionsWidget.cxx + cmCursesPathWidget.cxx + cmCursesStringWidget.cxx + cmCursesWidget.cxx + ) +target_include_directories(ccmake PRIVATE ${CURSES_INCLUDE_PATH}) target_link_libraries(ccmake CMakeLib) if(CMAKE_USE_SYSTEM_FORM) find_path(CURSES_FORM_INCLUDE_DIR NAMES form.h HINTS ${CURSES_INCLUDE_PATH} ${CURSES_INCLUDE_PATH}/ncurses) diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx index 47fe84c..561784c 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.cxx +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.cxx @@ -13,9 +13,11 @@ #include "cmStateTypes.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include "cmake.h" + +#include <cm/memory> #include <cassert> +#include <utility> #include <vector> cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( @@ -24,61 +26,65 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( , LabelWidth(labelwidth) , EntryWidth(entrywidth) { - this->Label = new cmCursesLabelWidget(this->LabelWidth, 1, 1, 1, key); - this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, " "); - this->Entry = nullptr; - this->Entry = new cmCursesStringWidget(this->EntryWidth, 1, 1, 1); + this->Label = + cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key); + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " "); + this->Entry = + cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1); } cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( - const std::string& key, cmake* cm, bool isNew, int labelwidth, + const std::string& key, cmState* state, bool isNew, int labelwidth, int entrywidth) : Key(key) , LabelWidth(labelwidth) , EntryWidth(entrywidth) { - this->Label = new cmCursesLabelWidget(this->LabelWidth, 1, 1, 1, key); + this->Label = + cm::make_unique<cmCursesLabelWidget>(this->LabelWidth, 1, 1, 1, key); if (isNew) { - this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, "*"); + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, "*"); } else { - this->IsNewLabel = new cmCursesLabelWidget(1, 1, 1, 1, " "); + this->IsNewLabel = cm::make_unique<cmCursesLabelWidget>(1, 1, 1, 1, " "); } - this->Entry = nullptr; - const char* value = cm->GetState()->GetCacheEntryValue(key); + const char* value = state->GetCacheEntryValue(key); assert(value); - switch (cm->GetState()->GetCacheEntryType(key)) { - case cmStateEnums::BOOL: - this->Entry = new cmCursesBoolWidget(this->EntryWidth, 1, 1, 1); - if (cmIsOn(value)) { - static_cast<cmCursesBoolWidget*>(this->Entry)->SetValueAsBool(true); - } else { - static_cast<cmCursesBoolWidget*>(this->Entry)->SetValueAsBool(false); - } + switch (state->GetCacheEntryType(key)) { + case cmStateEnums::BOOL: { + auto bw = cm::make_unique<cmCursesBoolWidget>(this->EntryWidth, 1, 1, 1); + bw->SetValueAsBool(cmIsOn(value)); + this->Entry = std::move(bw); break; - case cmStateEnums::PATH: - this->Entry = new cmCursesPathWidget(this->EntryWidth, 1, 1, 1); - static_cast<cmCursesPathWidget*>(this->Entry)->SetString(value); + } + case cmStateEnums::PATH: { + auto pw = cm::make_unique<cmCursesPathWidget>(this->EntryWidth, 1, 1, 1); + pw->SetString(value); + this->Entry = std::move(pw); break; - case cmStateEnums::FILEPATH: - this->Entry = new cmCursesFilePathWidget(this->EntryWidth, 1, 1, 1); - static_cast<cmCursesFilePathWidget*>(this->Entry)->SetString(value); + } + case cmStateEnums::FILEPATH: { + auto fpw = + cm::make_unique<cmCursesFilePathWidget>(this->EntryWidth, 1, 1, 1); + fpw->SetString(value); + this->Entry = std::move(fpw); break; + } case cmStateEnums::STRING: { - const char* stringsProp = - cm->GetState()->GetCacheEntryProperty(key, "STRINGS"); + const char* stringsProp = state->GetCacheEntryProperty(key, "STRINGS"); if (stringsProp) { - cmCursesOptionsWidget* ow = - new cmCursesOptionsWidget(this->EntryWidth, 1, 1, 1); - this->Entry = ow; - std::vector<std::string> options = cmExpandedList(stringsProp); - for (auto const& opt : options) { + auto ow = + cm::make_unique<cmCursesOptionsWidget>(this->EntryWidth, 1, 1, 1); + for (std::string const& opt : cmExpandedList(stringsProp)) { ow->AddOption(opt); } ow->SetOption(value); + this->Entry = std::move(ow); } else { - this->Entry = new cmCursesStringWidget(this->EntryWidth, 1, 1, 1); - static_cast<cmCursesStringWidget*>(this->Entry)->SetString(value); + auto sw = + cm::make_unique<cmCursesStringWidget>(this->EntryWidth, 1, 1, 1); + sw->SetString(value); + this->Entry = std::move(sw); } break; } @@ -91,12 +97,7 @@ cmCursesCacheEntryComposite::cmCursesCacheEntryComposite( } } -cmCursesCacheEntryComposite::~cmCursesCacheEntryComposite() -{ - delete this->Label; - delete this->IsNewLabel; - delete this->Entry; -} +cmCursesCacheEntryComposite::~cmCursesCacheEntryComposite() = default; const char* cmCursesCacheEntryComposite::GetValue() { diff --git a/Source/CursesDialog/cmCursesCacheEntryComposite.h b/Source/CursesDialog/cmCursesCacheEntryComposite.h index 0a69d3a..a711363 100644 --- a/Source/CursesDialog/cmCursesCacheEntryComposite.h +++ b/Source/CursesDialog/cmCursesCacheEntryComposite.h @@ -5,33 +5,38 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include <memory> #include <string> class cmCursesLabelWidget; class cmCursesWidget; -class cmake; +class cmState; class cmCursesCacheEntryComposite { public: cmCursesCacheEntryComposite(const std::string& key, int labelwidth, int entrywidth); - cmCursesCacheEntryComposite(const std::string& key, cmake* cm, bool isNew, - int labelwidth, int entrywidth); + cmCursesCacheEntryComposite(const std::string& key, cmState* state, + bool isNew, int labelwidth, int entrywidth); ~cmCursesCacheEntryComposite(); cmCursesCacheEntryComposite(cmCursesCacheEntryComposite const&) = delete; cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite const&) = delete; + cmCursesCacheEntryComposite(cmCursesCacheEntryComposite&&) = default; + cmCursesCacheEntryComposite& operator=(cmCursesCacheEntryComposite&&) = + default; + const char* GetValue(); friend class cmCursesMainForm; protected: - cmCursesLabelWidget* Label; - cmCursesLabelWidget* IsNewLabel; - cmCursesWidget* Entry; + std::unique_ptr<cmCursesLabelWidget> Label; + std::unique_ptr<cmCursesLabelWidget> IsNewLabel; + std::unique_ptr<cmCursesWidget> Entry; std::string Key; int LabelWidth; int EntryWidth; diff --git a/Source/CursesDialog/cmCursesMainForm.cxx b/Source/CursesDialog/cmCursesMainForm.cxx index 5f8a19e..219771b 100644 --- a/Source/CursesDialog/cmCursesMainForm.cxx +++ b/Source/CursesDialog/cmCursesMainForm.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCursesMainForm.h" -#include "cmAlgorithms.h" #include "cmCursesCacheEntryComposite.h" #include "cmCursesDummyWidget.h" #include "cmCursesForm.h" @@ -18,6 +17,8 @@ #include "cmVersion.h" #include "cmake.h" +#include <cm/memory> + #include <algorithm> #include <cstdio> #include <cstring> @@ -34,8 +35,6 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args, , InitialWidth(initWidth) { this->NumberOfPages = 0; - this->Fields = nullptr; - this->Entries = nullptr; this->AdvancedMode = false; this->NumberOfVisibleEntries = 0; this->OkToGenerate = false; @@ -43,7 +42,8 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args, "Welcome to ccmake, curses based user interface for CMake."); this->HelpMessage.emplace_back(); this->HelpMessage.emplace_back(s_ConstHelpMessage); - this->CMakeInstance = new cmake(cmake::RoleProject, cmState::Project); + this->CMakeInstance = + cm::make_unique<cmake>(cmake::RoleProject, cmState::Project); this->CMakeInstance->SetCMakeEditCommand( cmSystemTools::GetCMakeCursesCommand()); @@ -52,8 +52,6 @@ cmCursesMainForm::cmCursesMainForm(std::vector<std::string> args, cmStrCat(cmSystemTools::GetProgramPath(this->Args[0]), "/cmake"); this->Args[0] = whereCMake; this->CMakeInstance->SetArgs(this->Args); - this->SearchString = ""; - this->OldSearchString = ""; this->SearchMode = false; } @@ -64,27 +62,15 @@ cmCursesMainForm::~cmCursesMainForm() free_form(this->Form); this->Form = nullptr; } - delete[] this->Fields; - - // Clean-up composites - if (this->Entries) { - cmDeleteAll(*this->Entries); - } - delete this->Entries; - if (this->CMakeInstance) { - delete this->CMakeInstance; - this->CMakeInstance = nullptr; - } } // See if a cache entry is in the list of entries in the ui. bool cmCursesMainForm::LookForCacheEntry(const std::string& key) { - return this->Entries && - std::any_of(this->Entries->begin(), this->Entries->end(), - [&key](cmCursesCacheEntryComposite* entry) { - return key == entry->Key; - }); + return std::any_of(this->Entries.begin(), this->Entries.end(), + [&key](cmCursesCacheEntryComposite const& entry) { + return key == entry.Key; + }); } // Create new cmCursesCacheEntryComposite entries from the cache @@ -92,11 +78,10 @@ void cmCursesMainForm::InitializeUI() { // Create a vector of cmCursesCacheEntryComposite's // which contain labels, entries and new entry markers - std::vector<cmCursesCacheEntryComposite*>* newEntries = - new std::vector<cmCursesCacheEntryComposite*>; + std::vector<cmCursesCacheEntryComposite> newEntries; std::vector<std::string> cacheKeys = this->CMakeInstance->GetState()->GetCacheEntryKeys(); - newEntries->reserve(cacheKeys.size()); + newEntries.reserve(cacheKeys.size()); // Count non-internal and non-static entries int count = 0; @@ -112,13 +97,12 @@ void cmCursesMainForm::InitializeUI() int entrywidth = this->InitialWidth - 35; - cmCursesCacheEntryComposite* comp; if (count == 0) { // If cache is empty, display a label saying so and a // dummy entry widget (does not respond to input) - comp = new cmCursesCacheEntryComposite("EMPTY CACHE", 30, 30); - comp->Entry = new cmCursesDummyWidget(1, 1, 1, 1); - newEntries->push_back(comp); + cmCursesCacheEntryComposite comp("EMPTY CACHE", 30, 30); + comp.Entry = cm::make_unique<cmCursesDummyWidget>(1, 1, 1, 1); + newEntries.emplace_back(std::move(comp)); } else { // Create the composites. @@ -132,8 +116,8 @@ void cmCursesMainForm::InitializeUI() } if (!this->LookForCacheEntry(key)) { - newEntries->push_back(new cmCursesCacheEntryComposite( - key, this->CMakeInstance, true, 30, entrywidth)); + newEntries.emplace_back(key, this->CMakeInstance->GetState(), true, 30, + entrywidth); this->OkToGenerate = false; } } @@ -148,18 +132,14 @@ void cmCursesMainForm::InitializeUI() } if (this->LookForCacheEntry(key)) { - newEntries->push_back(new cmCursesCacheEntryComposite( - key, this->CMakeInstance, false, 30, entrywidth)); + newEntries.emplace_back(key, this->CMakeInstance->GetState(), false, + 30, entrywidth); } } } - // Clean old entries - if (this->Entries) { - cmDeleteAll(*this->Entries); - } - delete this->Entries; - this->Entries = newEntries; + // Replace old entries + this->Entries = std::move(newEntries); // Compute fields from composites this->RePost(); @@ -173,18 +153,18 @@ void cmCursesMainForm::RePost() free_form(this->Form); this->Form = nullptr; } - delete[] this->Fields; + this->Fields.clear(); if (this->AdvancedMode) { - this->NumberOfVisibleEntries = this->Entries->size(); + this->NumberOfVisibleEntries = this->Entries.size(); } else { // If normal mode, count only non-advanced entries this->NumberOfVisibleEntries = 0; - for (cmCursesCacheEntryComposite* entry : *this->Entries) { + for (cmCursesCacheEntryComposite& entry : this->Entries) { const char* existingValue = - this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue()); + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( - entry->GetValue(), "ADVANCED"); + entry.GetValue(), "ADVANCED"); if (!existingValue || (!this->AdvancedMode && advanced)) { continue; } @@ -197,38 +177,32 @@ void cmCursesMainForm::RePost() } // Assign the fields: 3 for each entry: label, new entry marker // ('*' or ' ') and entry widget - this->Fields = new FIELD*[3 * this->NumberOfVisibleEntries + 1]; - size_t cc; - for (cc = 0; cc < 3 * this->NumberOfVisibleEntries + 1; cc++) { - this->Fields[cc] = nullptr; - } + this->Fields.reserve(3 * this->NumberOfVisibleEntries + 1); // Assign fields - int j = 0; - for (cmCursesCacheEntryComposite* entry : *this->Entries) { + for (cmCursesCacheEntryComposite& entry : this->Entries) { const char* existingValue = - this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue()); + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( - entry->GetValue(), "ADVANCED"); + entry.GetValue(), "ADVANCED"); if (!existingValue || (!this->AdvancedMode && advanced)) { continue; } - this->Fields[3 * j] = entry->Label->Field; - this->Fields[3 * j + 1] = entry->IsNewLabel->Field; - this->Fields[3 * j + 2] = entry->Entry->Field; - j++; + this->Fields.push_back(entry.Label->Field); + this->Fields.push_back(entry.IsNewLabel->Field); + this->Fields.push_back(entry.Entry->Field); } // if no cache entries there should still be one dummy field - if (j == 0) { - const auto& front = *this->Entries->front(); - this->Fields[0] = front.Label->Field; - this->Fields[1] = front.IsNewLabel->Field; - this->Fields[2] = front.Entry->Field; + if (this->Fields.empty()) { + const auto& front = this->Entries.front(); + this->Fields.push_back(front.Label->Field); + this->Fields.push_back(front.IsNewLabel->Field); + this->Fields.push_back(front.Entry->Field); this->NumberOfVisibleEntries = 1; } // Has to be null terminated. - this->Fields[3 * this->NumberOfVisibleEntries] = nullptr; + this->Fields.push_back(nullptr); } void cmCursesMainForm::Render(int left, int top, int width, int height) @@ -261,16 +235,16 @@ void cmCursesMainForm::Render(int left, int top, int width, int height) height -= 7; if (this->AdvancedMode) { - this->NumberOfVisibleEntries = this->Entries->size(); + this->NumberOfVisibleEntries = this->Entries.size(); } else { // If normal, display only non-advanced entries this->NumberOfVisibleEntries = 0; - for (cmCursesCacheEntryComposite* entry : *this->Entries) { + for (cmCursesCacheEntryComposite& entry : this->Entries) { const char* existingValue = - this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue()); + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( - entry->GetValue(), "ADVANCED"); + entry.GetValue(), "ADVANCED"); if (!existingValue || (!this->AdvancedMode && advanced)) { continue; } @@ -283,12 +257,12 @@ void cmCursesMainForm::Render(int left, int top, int width, int height) if (height > 0) { bool isNewPage; int i = 0; - for (cmCursesCacheEntryComposite* entry : *this->Entries) { + for (cmCursesCacheEntryComposite& entry : this->Entries) { const char* existingValue = - this->CMakeInstance->GetState()->GetCacheEntryValue(entry->GetValue()); + this->CMakeInstance->GetState()->GetCacheEntryValue(entry.GetValue()); bool advanced = this->CMakeInstance->GetState()->GetCacheEntryPropertyAsBool( - entry->GetValue(), "ADVANCED"); + entry.GetValue(), "ADVANCED"); if (!existingValue || (!this->AdvancedMode && advanced)) { continue; } @@ -299,16 +273,16 @@ void cmCursesMainForm::Render(int left, int top, int width, int height) if (isNewPage) { this->NumberOfPages++; } - entry->Label->Move(left, top + row - 1, isNewPage); - entry->IsNewLabel->Move(left + 32, top + row - 1, false); - entry->Entry->Move(left + 33, top + row - 1, false); - entry->Entry->SetPage(this->NumberOfPages); + entry.Label->Move(left, top + row - 1, isNewPage); + entry.IsNewLabel->Move(left + 32, top + row - 1, false); + entry.Entry->Move(left + 33, top + row - 1, false); + entry.Entry->SetPage(this->NumberOfPages); i++; } } // Post the form - this->Form = new_form(this->Fields); + this->Form = new_form(this->Fields.data()); post_form(this->Form); // Update toolbar this->UpdateStatusBar(); @@ -655,28 +629,28 @@ void cmCursesMainForm::RemoveEntry(const char* value) } auto removeIt = - std::find_if(this->Entries->begin(), this->Entries->end(), - [value](cmCursesCacheEntryComposite* entry) -> bool { - const char* val = entry->GetValue(); + std::find_if(this->Entries.begin(), this->Entries.end(), + [value](cmCursesCacheEntryComposite& entry) -> bool { + const char* val = entry.GetValue(); return val != nullptr && !strcmp(value, val); }); - if (removeIt != this->Entries->end()) { + if (removeIt != this->Entries.end()) { this->CMakeInstance->UnwatchUnusedCli(value); - this->Entries->erase(removeIt); + this->Entries.erase(removeIt); } } // copy from the list box to the cache manager void cmCursesMainForm::FillCacheManagerFromUI() { - for (cmCursesCacheEntryComposite* entry : *this->Entries) { - const std::string& cacheKey = entry->Key; + for (cmCursesCacheEntryComposite& entry : this->Entries) { + const std::string& cacheKey = entry.Key; const char* existingValue = this->CMakeInstance->GetState()->GetCacheEntryValue(cacheKey); if (existingValue) { std::string oldValue = existingValue; - std::string newValue = entry->Entry->GetValue(); + std::string newValue = entry.Entry->GetValue(); std::string fixedOldValue; std::string fixedNewValue; cmStateEnums::CacheEntryType t = @@ -762,7 +736,7 @@ void cmCursesMainForm::HandleInput() this->JumpToCacheEntry(this->SearchString.c_str()); this->OldSearchString = this->SearchString; } - this->SearchString = ""; + this->SearchString.clear(); } /* else if ( key == KEY_ESCAPE ) @@ -778,7 +752,7 @@ void cmCursesMainForm::HandleInput() } } else if (key == ctrl('h') || key == KEY_BACKSPACE || key == KEY_DC) { if (!this->SearchString.empty()) { - this->SearchString.resize(this->SearchString.size() - 1); + this->SearchString.pop_back(); } } } else if (currentWidget && !this->SearchMode) { @@ -867,17 +841,9 @@ void cmCursesMainForm::HandleInput() curField, "HELPSTRING"); } if (helpString) { - char* message = new char - [strlen(curField) + strlen(helpString) + - strlen( - "Current option is: \n Help string for this option is: \n") + - 10]; - sprintf( - message, - "Current option is: %s\nHelp string for this option is: %s\n", - curField, helpString); - this->HelpMessage[1] = message; - delete[] message; + this->HelpMessage[1] = + cmStrCat("Current option is: ", curField, '\n', + "Help string for this option is: ", helpString, '\n'); } else { this->HelpMessage[1] = ""; } @@ -973,14 +939,14 @@ void cmCursesMainForm::HandleInput() if (nextCur) { // make the next or prev. current field after deletion - auto nextEntryIt = - std::find_if(this->Entries->begin(), this->Entries->end(), - [&nextVal](cmCursesCacheEntryComposite* entry) { - return nextVal == entry->Key; - }); - - if (nextEntryIt != this->Entries->end()) { - set_current_field(this->Form, (*nextEntryIt)->Entry->Field); + auto nextEntryIt = std::find_if( + this->Entries.begin(), this->Entries.end(), + [&nextVal](cmCursesCacheEntryComposite const& entry) { + return nextVal == entry.Key; + }); + + if (nextEntryIt != this->Entries.end()) { + set_current_field(this->Form, nextEntryIt->Entry->Field); } } } diff --git a/Source/CursesDialog/cmCursesMainForm.h b/Source/CursesDialog/cmCursesMainForm.h index f3194ab..48d1791 100644 --- a/Source/CursesDialog/cmCursesMainForm.h +++ b/Source/CursesDialog/cmCursesMainForm.h @@ -5,15 +5,16 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cmCursesCacheEntryComposite.h" #include "cmCursesForm.h" #include "cmCursesStandardIncludes.h" #include "cmStateTypes.h" #include <cstddef> +#include <memory> #include <string> #include <vector> -class cmCursesCacheEntryComposite; class cmake; /** \class cmCursesMainForm @@ -122,7 +123,7 @@ protected: void JumpToCacheEntry(const char* str); // Copies of cache entries stored in the user interface - std::vector<cmCursesCacheEntryComposite*>* Entries; + std::vector<cmCursesCacheEntryComposite> Entries; // Errors produced during last run of cmake std::vector<std::string> Errors; // Command line arguments to be passed to cmake each time @@ -136,11 +137,7 @@ protected: static const char* s_ConstHelpMessage; // Fields displayed. Includes labels, new entry markers, entries - FIELD** Fields; - // Where is source of current project - std::string WhereSource; - // Where is cmake executable - std::string WhereCMake; + std::vector<FIELD*> Fields; // Number of entries shown (depends on mode -normal or advanced-) size_t NumberOfVisibleEntries; bool AdvancedMode; @@ -150,7 +147,7 @@ protected: int NumberOfPages; int InitialWidth; - cmake* CMakeInstance; + std::unique_ptr<cmake> CMakeInstance; std::string SearchString; std::string OldSearchString; diff --git a/Source/CursesDialog/cmCursesStringWidget.cxx b/Source/CursesDialog/cmCursesStringWidget.cxx index 3fc1858..d3a05e8 100644 --- a/Source/CursesDialog/cmCursesStringWidget.cxx +++ b/Source/CursesDialog/cmCursesStringWidget.cxx @@ -9,7 +9,6 @@ #include "cmStateTypes.h" #include <cstdio> -#include <cstring> inline int ctrl(int z) { @@ -35,13 +34,13 @@ void cmCursesStringWidget::OnTab(cmCursesMainForm* /*unused*/, void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW* /*unused*/) { - FORM* form = fm->GetForm(); if (this->InEdit) { cmCursesForm::LogMessage("String widget leaving edit."); this->InEdit = false; fm->PrintKeys(); - delete[] this->OriginalString; + this->OriginalString.clear(); // trick to force forms to update the field buffer + FORM* form = fm->GetForm(); form_driver(form, REQ_NEXT_FIELD); form_driver(form, REQ_PREV_FIELD); this->Done = true; @@ -49,9 +48,7 @@ void cmCursesStringWidget::OnReturn(cmCursesMainForm* fm, WINDOW* /*unused*/) cmCursesForm::LogMessage("String widget entering edit."); this->InEdit = true; fm->PrintKeys(); - char* buf = field_buffer(this->Field, 0); - this->OriginalString = new char[strlen(buf) + 1]; - strcpy(this->OriginalString, buf); + this->OriginalString = field_buffer(this->Field, 0); } } @@ -75,7 +72,7 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, return false; } - this->OriginalString = nullptr; + this->OriginalString.clear(); this->Done = false; char debugMessage[128]; @@ -113,7 +110,7 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, key == ctrl('p') || key == KEY_NPAGE || key == ctrl('d') || key == KEY_PPAGE || key == ctrl('u')) { this->InEdit = false; - delete[] this->OriginalString; + this->OriginalString.clear(); // trick to force forms to update the field buffer form_driver(form, REQ_NEXT_FIELD); form_driver(form, REQ_PREV_FIELD); @@ -125,7 +122,7 @@ bool cmCursesStringWidget::HandleInput(int& key, cmCursesMainForm* fm, this->InEdit = false; fm->PrintKeys(); this->SetString(this->OriginalString); - delete[] this->OriginalString; + this->OriginalString.clear(); touchwin(w); wrefresh(w); return true; @@ -188,23 +185,18 @@ bool cmCursesStringWidget::PrintKeys() } if (this->InEdit) { char fmt_s[] = "%s"; - char firstLine[512]; // Clean the toolbar - memset(firstLine, ' ', sizeof(firstLine)); - firstLine[511] = '\0'; curses_move(y - 4, 0); - printw(fmt_s, firstLine); - curses_move(y - 3, 0); - printw(fmt_s, firstLine); - curses_move(y - 2, 0); - printw(fmt_s, firstLine); - curses_move(y - 1, 0); - printw(fmt_s, firstLine); - + clrtoeol(); curses_move(y - 3, 0); printw(fmt_s, "Editing option, press [enter] to confirm"); + clrtoeol(); curses_move(y - 2, 0); printw(fmt_s, " press [esc] to cancel"); + clrtoeol(); + curses_move(y - 1, 0); + clrtoeol(); + return true; } return false; diff --git a/Source/CursesDialog/cmCursesStringWidget.h b/Source/CursesDialog/cmCursesStringWidget.h index 021515b..a41f0e8 100644 --- a/Source/CursesDialog/cmCursesStringWidget.h +++ b/Source/CursesDialog/cmCursesStringWidget.h @@ -23,9 +23,6 @@ class cmCursesStringWidget : public cmCursesWidget public: cmCursesStringWidget(int width, int height, int left, int top); - cmCursesStringWidget(cmCursesStringWidget const&) = delete; - cmCursesStringWidget& operator=(cmCursesStringWidget const&) = delete; - /** * Handle user input. Called by the container of this widget * when this widget has focus. Returns true if the input was @@ -65,7 +62,7 @@ public: protected: // true if the widget is in edit mode bool InEdit; - char* OriginalString; + std::string OriginalString; bool Done; }; diff --git a/Source/cmGeneratorExpressionNode.cxx b/Source/cmGeneratorExpressionNode.cxx index 641cbaf..5a35007 100644 --- a/Source/cmGeneratorExpressionNode.cxx +++ b/Source/cmGeneratorExpressionNode.cxx @@ -707,7 +707,8 @@ struct CompilerIdNode : public cmGeneratorExpressionNode }; static const CompilerIdNode cCompilerIdNode("C"), cxxCompilerIdNode("CXX"), - cudaCompilerIdNode("CUDA"), fortranCompilerIdNode("Fortran"); + cudaCompilerIdNode("CUDA"), objcCompilerIdNode("OBJC"), + objcxxCompilerIdNode("OBJCXX"), fortranCompilerIdNode("Fortran"); struct CompilerVersionNode : public cmGeneratorExpressionNode { @@ -771,6 +772,7 @@ struct CompilerVersionNode : public cmGeneratorExpressionNode static const CompilerVersionNode cCompilerVersionNode("C"), cxxCompilerVersionNode("CXX"), cudaCompilerVersionNode("CUDA"), + objcCompilerVersionNode("OBJC"), objcxxCompilerVersionNode("OBJCXX"), fortranCompilerVersionNode("Fortran"); struct PlatformIdNode : public cmGeneratorExpressionNode @@ -2243,6 +2245,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "NOT", ¬Node }, { "C_COMPILER_ID", &cCompilerIdNode }, { "CXX_COMPILER_ID", &cxxCompilerIdNode }, + { "OBJC_COMPILER_ID", &objcCompilerIdNode }, + { "OBJCXX_COMPILER_ID", &objcxxCompilerIdNode }, { "CUDA_COMPILER_ID", &cudaCompilerIdNode }, { "Fortran_COMPILER_ID", &fortranCompilerIdNode }, { "VERSION_GREATER", &versionGreaterNode }, @@ -2253,6 +2257,8 @@ const cmGeneratorExpressionNode* cmGeneratorExpressionNode::GetNode( { "C_COMPILER_VERSION", &cCompilerVersionNode }, { "CXX_COMPILER_VERSION", &cxxCompilerVersionNode }, { "CUDA_COMPILER_VERSION", &cudaCompilerVersionNode }, + { "OBJC_COMPILER_VERSION", &objcCompilerVersionNode }, + { "OBJCXX_COMPILER_VERSION", &objcxxCompilerVersionNode }, { "Fortran_COMPILER_VERSION", &fortranCompilerVersionNode }, { "PLATFORM_ID", &platformIdNode }, { "COMPILE_FEATURES", &compileFeaturesNode }, diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 7af3da5..6e6ca51 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -1655,7 +1655,7 @@ void cmLocalGenerator::AddArchitectureFlags(std::string& flags, const char* deploymentTargetFlag = this->Makefile->GetDefinition(deploymentTargetFlagVar); if (!archs.empty() && !lang.empty() && - (lang[0] == 'C' || lang[0] == 'F')) { + (lang[0] == 'C' || lang[0] == 'F' || lang[0] == 'O')) { for (std::string const& arch : archs) { flags += " -arch "; flags += arch; @@ -1942,10 +1942,20 @@ void cmLocalGenerator::AddCompilerRequirementFlag( langStdMap["CXX"].emplace_back("11"); langStdMap["CXX"].emplace_back("98"); + langStdMap["OBJCXX"].emplace_back("20"); + langStdMap["OBJCXX"].emplace_back("17"); + langStdMap["OBJCXX"].emplace_back("14"); + langStdMap["OBJCXX"].emplace_back("11"); + langStdMap["OBJCXX"].emplace_back("98"); + langStdMap["C"].emplace_back("11"); langStdMap["C"].emplace_back("99"); langStdMap["C"].emplace_back("90"); + langStdMap["OBJC"].emplace_back("11"); + langStdMap["OBJC"].emplace_back("99"); + langStdMap["OBJC"].emplace_back("90"); + langStdMap["CUDA"].emplace_back("14"); langStdMap["CUDA"].emplace_back("11"); langStdMap["CUDA"].emplace_back("98"); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 640f823..d9fbe9d 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -38,6 +38,7 @@ #include "cmState.h" #include "cmStateDirectory.h" #include "cmStateTypes.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmTarget.h" #include "cmTargetLinkLibraryType.h" @@ -4627,9 +4628,9 @@ bool cmMakefile::AddRequiredTargetFeature(cmTarget* target, target->AppendProperty("COMPILE_FEATURES", feature.c_str()); - return lang == "C" - ? this->AddRequiredTargetCFeature(target, feature, error) - : this->AddRequiredTargetCxxFeature(target, feature, error); + return lang == "C" || lang == "OBJC" + ? this->AddRequiredTargetCFeature(target, feature, lang, error) + : this->AddRequiredTargetCxxFeature(target, feature, lang, error); } bool cmMakefile::CompileFeatureKnown(cmTarget const* target, @@ -4721,30 +4722,33 @@ bool cmMakefile::HaveStandardAvailable(cmTarget const* target, std::string const& lang, const std::string& feature) const { - return lang == "C" ? this->HaveCStandardAvailable(target, feature) - : this->HaveCxxStandardAvailable(target, feature); + return lang == "C" || lang == "OBJC" + ? this->HaveCStandardAvailable(target, feature, lang) + : this->HaveCxxStandardAvailable(target, feature, lang); } bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, - const std::string& feature) const + const std::string& feature, + std::string const& lang) const { const char* defaultCStandard = - this->GetDefinition("CMAKE_C_STANDARD_DEFAULT"); + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (!defaultCStandard) { this->IssueMessage( MessageType::INTERNAL_ERROR, - "CMAKE_C_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " - "not fully configured for this compiler."); + cmStrCat("CMAKE_", lang, + "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler.")); // Return true so the caller does not try to lookup the default standard. return true; } if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(defaultCStandard)) == cm::cend(C_STANDARDS)) { - std::ostringstream e; - e << "The CMAKE_C_STANDARD_DEFAULT variable contains an " - "invalid value: \"" - << defaultCStandard << "\"."; - this->IssueMessage(MessageType::INTERNAL_ERROR, e.str()); + const std::string e = cmStrCat("The CMAKE_", lang, + "_STANDARD_DEFAULT variable contains an " + "invalid value: \"", + defaultCStandard, "\"."); + this->IssueMessage(MessageType::INTERNAL_ERROR, e); return false; } @@ -4752,19 +4756,20 @@ bool cmMakefile::HaveCStandardAvailable(cmTarget const* target, bool needC99 = false; bool needC11 = false; - this->CheckNeededCLanguage(feature, needC90, needC99, needC11); + this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - const char* existingCStandard = target->GetProperty("C_STANDARD"); + const char* existingCStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); if (!existingCStandard) { existingCStandard = defaultCStandard; } if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { - std::ostringstream e; - e << "The C_STANDARD property on target \"" << target->GetName() - << "\" contained an invalid value: \"" << existingCStandard << "\"."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCStandard, "\"."); + this->IssueMessage(MessageType::FATAL_ERROR, e); return false; } @@ -4795,7 +4800,7 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, std::string const& lhs, std::string const& rhs) { - if (lang == "C") { + if (lang == "C" || lang == "OBJC") { const char* const* rhsIt = std::find_if( cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(rhs)); @@ -4810,25 +4815,26 @@ bool cmMakefile::IsLaterStandard(std::string const& lang, } bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature) const + const std::string& feature, + std::string const& lang) const { const char* defaultCxxStandard = - this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (!defaultCxxStandard) { this->IssueMessage( MessageType::INTERNAL_ERROR, - "CMAKE_CXX_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " - "not fully configured for this compiler."); + cmStrCat("CMAKE_", lang, + "_STANDARD_DEFAULT is not set. COMPILE_FEATURES support " + "not fully configured for this compiler.")); // Return true so the caller does not try to lookup the default standard. return true; } if (std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(defaultCxxStandard)) == cm::cend(CXX_STANDARDS)) { - std::ostringstream e; - e << "The CMAKE_CXX_STANDARD_DEFAULT variable contains an " - "invalid value: \"" - << defaultCxxStandard << "\"."; - this->IssueMessage(MessageType::INTERNAL_ERROR, e.str()); + const std::string e = + cmStrCat("The CMAKE_", lang, "_STANDARD_DEFAULT variable contains an ", + "invalid value: \"", defaultCxxStandard, "\"."); + this->IssueMessage(MessageType::INTERNAL_ERROR, e); return false; } @@ -4837,10 +4843,11 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, bool needCxx14 = false; bool needCxx17 = false; bool needCxx20 = false; - this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, + this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); + const char* existingCxxStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); if (!existingCxxStandard) { existingCxxStandard = defaultCxxStandard; } @@ -4849,10 +4856,10 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { - std::ostringstream e; - e << "The CXX_STANDARD property on target \"" << target->GetName() - << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; - this->IssueMessage(MessageType::FATAL_ERROR, e.str()); + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCxxStandard, "\"."); + this->IssueMessage(MessageType::FATAL_ERROR, e); return false; } @@ -4870,32 +4877,33 @@ bool cmMakefile::HaveCxxStandardAvailable(cmTarget const* target, } void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, + std::string const& lang, bool& needCxx98, bool& needCxx11, bool& needCxx14, bool& needCxx17, bool& needCxx20) const { if (const char* propCxx98 = - this->GetDefinition("CMAKE_CXX98_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "98_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx98); needCxx98 = cmContains(props, feature); } if (const char* propCxx11 = - this->GetDefinition("CMAKE_CXX11_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx11); needCxx11 = cmContains(props, feature); } if (const char* propCxx14 = - this->GetDefinition("CMAKE_CXX14_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "14_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx14); needCxx14 = cmContains(props, feature); } if (const char* propCxx17 = - this->GetDefinition("CMAKE_CXX17_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "17_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx17); needCxx17 = cmContains(props, feature); } if (const char* propCxx20 = - this->GetDefinition("CMAKE_CXX20_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "20_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propCxx20); needCxx20 = cmContains(props, feature); } @@ -4903,6 +4911,7 @@ void cmMakefile::CheckNeededCxxLanguage(const std::string& feature, bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, const std::string& feature, + std::string const& lang, std::string* error) const { bool needCxx98 = false; @@ -4911,13 +4920,14 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, bool needCxx17 = false; bool needCxx20 = false; - this->CheckNeededCxxLanguage(feature, needCxx98, needCxx11, needCxx14, + this->CheckNeededCxxLanguage(feature, lang, needCxx98, needCxx11, needCxx14, needCxx17, needCxx20); - const char* existingCxxStandard = target->GetProperty("CXX_STANDARD"); + const char* existingCxxStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); if (existingCxxStandard == nullptr) { const char* defaultCxxStandard = - this->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (defaultCxxStandard && *defaultCxxStandard) { existingCxxStandard = defaultCxxStandard; } @@ -4928,14 +4938,14 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, std::find_if(cm::cbegin(CXX_STANDARDS), cm::cend(CXX_STANDARDS), cmStrCmp(existingCxxStandard)); if (existingCxxLevel == cm::cend(CXX_STANDARDS)) { - std::ostringstream e; - e << "The CXX_STANDARD property on target \"" << target->GetName() - << "\" contained an invalid value: \"" << existingCxxStandard << "\"."; + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCxxStandard, "\"."); if (error) { - *error = e.str(); + *error = e; } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, - e.str(), this->Backtrace); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, + this->Backtrace); } return false; } @@ -4976,7 +4986,7 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, // Ensure the C++ language level is high enough to support // the needed C++ features. if (!existingCxxLevel || existingCxxLevel < needCxxLevel) { - target->SetProperty("CXX_STANDARD", *needCxxLevel); + target->SetProperty(cmStrCat(lang, "_STANDARD"), *needCxxLevel); } // Ensure the CUDA language level is high enough to support @@ -4990,21 +5000,21 @@ bool cmMakefile::AddRequiredTargetCxxFeature(cmTarget* target, } void cmMakefile::CheckNeededCLanguage(const std::string& feature, - bool& needC90, bool& needC99, - bool& needC11) const + std::string const& lang, bool& needC90, + bool& needC99, bool& needC11) const { if (const char* propC90 = - this->GetDefinition("CMAKE_C90_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "90_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC90); needC90 = cmContains(props, feature); } if (const char* propC99 = - this->GetDefinition("CMAKE_C99_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "99_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC99); needC99 = cmContains(props, feature); } if (const char* propC11 = - this->GetDefinition("CMAKE_C11_COMPILE_FEATURES")) { + this->GetDefinition(cmStrCat("CMAKE_", lang, "11_COMPILE_FEATURES"))) { std::vector<std::string> props = cmExpandedList(propC11); needC11 = cmContains(props, feature); } @@ -5012,18 +5022,20 @@ void cmMakefile::CheckNeededCLanguage(const std::string& feature, bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, const std::string& feature, + std::string const& lang, std::string* error) const { bool needC90 = false; bool needC99 = false; bool needC11 = false; - this->CheckNeededCLanguage(feature, needC90, needC99, needC11); + this->CheckNeededCLanguage(feature, lang, needC90, needC99, needC11); - const char* existingCStandard = target->GetProperty("C_STANDARD"); + const char* existingCStandard = + target->GetProperty(cmStrCat(lang, "_STANDARD")); if (existingCStandard == nullptr) { const char* defaultCStandard = - this->GetDefinition("CMAKE_C_STANDARD_DEFAULT"); + this->GetDefinition(cmStrCat("CMAKE_", lang, "_STANDARD_DEFAULT")); if (defaultCStandard && *defaultCStandard) { existingCStandard = defaultCStandard; } @@ -5031,14 +5043,14 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, if (existingCStandard) { if (std::find_if(cm::cbegin(C_STANDARDS), cm::cend(C_STANDARDS), cmStrCmp(existingCStandard)) == cm::cend(C_STANDARDS)) { - std::ostringstream e; - e << "The C_STANDARD property on target \"" << target->GetName() - << "\" contained an invalid value: \"" << existingCStandard << "\"."; + const std::string e = cmStrCat( + "The ", lang, "_STANDARD property on target \"", target->GetName(), + "\" contained an invalid value: \"", existingCStandard, "\"."); if (error) { - *error = e.str(); + *error = e; } else { - this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, - e.str(), this->Backtrace); + this->GetCMakeInstance()->IssueMessage(MessageType::FATAL_ERROR, e, + this->Backtrace); } return false; } @@ -5069,11 +5081,11 @@ bool cmMakefile::AddRequiredTargetCFeature(cmTarget* target, } if (setC11) { - target->SetProperty("C_STANDARD", "11"); + target->SetProperty(cmStrCat(lang, "_STANDARD"), "11"); } else if (setC99) { - target->SetProperty("C_STANDARD", "99"); + target->SetProperty(cmStrCat(lang, "_STANDARD"), "99"); } else if (setC90) { - target->SetProperty("C_STANDARD", "90"); + target->SetProperty(cmStrCat(lang, "_STANDARD"), "90"); } return true; } diff --git a/Source/cmMakefile.h b/Source/cmMakefile.h index bb88bed..3a17aaf 100644 --- a/Source/cmMakefile.h +++ b/Source/cmMakefile.h @@ -1146,22 +1146,28 @@ private: bool MightHaveCustomCommand(const std::string& name) const; bool AddRequiredTargetCFeature(cmTarget* target, const std::string& feature, + std::string const& lang, std::string* error = nullptr) const; bool AddRequiredTargetCxxFeature(cmTarget* target, const std::string& feature, + std::string const& lang, std::string* error = nullptr) const; - void CheckNeededCLanguage(const std::string& feature, bool& needC90, + void CheckNeededCLanguage(const std::string& feature, + std::string const& lang, bool& needC90, bool& needC99, bool& needC11) const; - void CheckNeededCxxLanguage(const std::string& feature, bool& needCxx98, + void CheckNeededCxxLanguage(const std::string& feature, + std::string const& lang, bool& needCxx98, bool& needCxx11, bool& needCxx14, bool& needCxx17, bool& needCxx20) const; bool HaveCStandardAvailable(cmTarget const* target, - const std::string& feature) const; + const std::string& feature, + std::string const& lang) const; bool HaveCxxStandardAvailable(cmTarget const* target, - const std::string& feature) const; + const std::string& feature, + std::string const& lang) const; void CheckForUnusedVariables() const; diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index a9d4fee..1320b07 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -210,79 +210,18 @@ cmQtAutoGenerator::cmQtAutoGenerator(GenT genType) cmQtAutoGenerator::~cmQtAutoGenerator() = default; -bool cmQtAutoGenerator::Run(std::string const& infoFile, - std::string const& config) +bool cmQtAutoGenerator::InfoT::Read(std::istream& istr) { - // Info settings - InfoFile_ = infoFile; - cmSystemTools::CollapseFullPath(InfoFile_); - if (!InfoFileTime_.Load(InfoFile_)) { - cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ", - Quoted(InfoFile_), " is not readable\n")); - return false; - } - InfoDir_ = cmSystemTools::GetFilenamePath(infoFile); - InfoConfig_ = config; - - // Read info file - { - cmsys::ifstream ifs(InfoFile_.c_str(), (std::ios::in | std::ios::binary)); - if (!ifs) { - Log().Error(GenType_, - cmStrCat("Could not to open info file ", Quoted(InfoFile_))); - return false; - } - try { - ifs >> Info_; - } catch (...) { - Log().Error(GenType_, - cmStrCat("Could not read info file ", Quoted(InfoFile_))); - return false; - } - } - // Info: setup logger - { - unsigned int value = 0; - if (!InfoUInt("VERBOSITY", value, false)) { - return false; - } - Logger_.RaiseVerbosity(value); - } - // Info: setup project directories - if (!InfoString("CMAKE_SOURCE_DIR", ProjectDirs_.Source, true) || - !InfoString("CMAKE_BINARY_DIR", ProjectDirs_.Binary, true) || - !InfoString("CMAKE_CURRENT_SOURCE_DIR", ProjectDirs_.CurrentSource, - true) || - !InfoString("CMAKE_CURRENT_BINARY_DIR", ProjectDirs_.CurrentBinary, - true)) { - return false; - } - - if (!this->InitFromInfo()) { + try { + istr >> Json_; + } catch (...) { return false; } - // Clear info - Info_ = Json::nullValue; - - return this->Process(); -} - -bool cmQtAutoGenerator::LogInfoError(GenT genType, - cm::string_view message) const -{ - this->Log().Error( - genType, - cmStrCat("Info error in info file\n", Quoted(InfoFile()), ":\n", message)); - return false; -} - -bool cmQtAutoGenerator::LogInfoError(cm::string_view message) const -{ - return LogInfoError(GenType_, message); + return true; } -bool cmQtAutoGenerator::JsonGetArray(std::vector<std::string>& list, - Json::Value const& jval) +bool cmQtAutoGenerator::InfoT::GetJsonArray(std::vector<std::string>& list, + Json::Value const& jval) { Json::ArrayIndex const arraySize = jval.size(); if (arraySize == 0) { @@ -301,8 +240,8 @@ bool cmQtAutoGenerator::JsonGetArray(std::vector<std::string>& list, return picked; } -bool cmQtAutoGenerator::JsonGetArray(std::unordered_set<std::string>& list, - Json::Value const& jval) +bool cmQtAutoGenerator::InfoT::GetJsonArray( + std::unordered_set<std::string>& list, Json::Value const& jval) { Json::ArrayIndex const arraySize = jval.size(); if (arraySize == 0) { @@ -321,141 +260,157 @@ bool cmQtAutoGenerator::JsonGetArray(std::unordered_set<std::string>& list, return picked; } -std::string cmQtAutoGenerator::InfoConfigKey(std::string const& key) const +std::string cmQtAutoGenerator::InfoT::ConfigKey(cm::string_view key) const { - return cmStrCat(key, '_', InfoConfig()); + return cmStrCat(key, '_', Gen_.InfoConfig()); } -bool cmQtAutoGenerator::InfoString(std::string const& key, std::string& value, - bool required) const +bool cmQtAutoGenerator::InfoT::GetString(std::string const& key, + std::string& value, + bool required) const { - Json::Value const& jval = Info()[key]; + Json::Value const& jval = Json_[key]; if (!jval.isString()) { if (!jval.isNull() || required) { - return LogInfoError(cmStrCat(key, " is not a string.")); + return LogError(cmStrCat(key, " is not a string.")); } } else { value = jval.asString(); if (value.empty() && required) { - return LogInfoError(cmStrCat(key, " is empty.")); + return LogError(cmStrCat(key, " is empty.")); } } return true; } -bool cmQtAutoGenerator::InfoStringConfig(std::string const& key, - std::string& value, - - bool required) const +bool cmQtAutoGenerator::InfoT::GetStringConfig(std::string const& key, + std::string& value, + bool required) const { { // Try config - std::string const configKey = InfoConfigKey(key); - Json::Value const& jval = Info_[configKey]; + std::string const configKey = ConfigKey(key); + Json::Value const& jval = Json_[configKey]; if (!jval.isNull()) { if (!jval.isString()) { - return LogInfoError(cmStrCat(configKey, " is not a string.")); + return LogError(cmStrCat(configKey, " is not a string.")); } value = jval.asString(); if (required && value.empty()) { - return LogInfoError(cmStrCat(configKey, " is empty.")); + return LogError(cmStrCat(configKey, " is empty.")); } return true; } } // Try plain - return InfoString(key, value, required); + return GetString(key, value, required); } -bool cmQtAutoGenerator::InfoBool(std::string const& key, bool& value, - bool required) const +bool cmQtAutoGenerator::InfoT::GetBool(std::string const& key, bool& value, + bool required) const { - Json::Value const& jval = Info()[key]; + Json::Value const& jval = Json_[key]; if (jval.isBool()) { value = jval.asBool(); } else { if (!jval.isNull() || required) { - return LogInfoError(cmStrCat(key, " is not a boolean.")); + return LogError(cmStrCat(key, " is not a boolean.")); } } return true; } -bool cmQtAutoGenerator::InfoUInt(std::string const& key, unsigned int& value, - bool required) const +bool cmQtAutoGenerator::InfoT::GetUInt(std::string const& key, + unsigned int& value, + bool required) const { - Json::Value const& jval = Info()[key]; + Json::Value const& jval = Json_[key]; if (jval.isUInt()) { value = jval.asUInt(); } else { if (!jval.isNull() || required) { - return LogInfoError(cmStrCat(key, " is not an unsigned integer.")); + return LogError(cmStrCat(key, " is not an unsigned integer.")); } } return true; } -bool cmQtAutoGenerator::InfoArray(std::string const& key, - std::vector<std::string>& list, - bool required) const +bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key, + std::vector<std::string>& list, + bool required) const { - Json::Value const& jval = Info()[key]; + Json::Value const& jval = Json_[key]; if (!jval.isArray()) { if (!jval.isNull() || required) { - return LogInfoError(cmStrCat(key, " is not an array.")); + return LogError(cmStrCat(key, " is not an array.")); } } - return JsonGetArray(list, jval) || !required; + return GetJsonArray(list, jval) || !required; } -bool cmQtAutoGenerator::InfoArray(std::string const& key, - std::unordered_set<std::string>& list, - bool required) const +bool cmQtAutoGenerator::InfoT::GetArray(std::string const& key, + std::unordered_set<std::string>& list, + bool required) const { - Json::Value const& jval = Info()[key]; + Json::Value const& jval = Json_[key]; if (!jval.isArray()) { if (!jval.isNull() || required) { - return LogInfoError(cmStrCat(key, " is not an array.")); + return LogError(cmStrCat(key, " is not an array.")); } } - return JsonGetArray(list, jval) || !required; + return GetJsonArray(list, jval) || !required; } -bool cmQtAutoGenerator::InfoArrayConfig(std::string const& key, - std::vector<std::string>& list, - bool required) const +bool cmQtAutoGenerator::InfoT::GetArrayConfig(std::string const& key, + std::vector<std::string>& list, + bool required) const { { // Try config - std::string const configKey = InfoConfigKey(key); - Json::Value const& jval = Info()[configKey]; + std::string const configKey = ConfigKey(key); + Json::Value const& jval = Json_[configKey]; if (!jval.isNull()) { if (!jval.isArray()) { - return LogInfoError(cmStrCat(configKey, " is not an array string.")); + return LogError(cmStrCat(configKey, " is not an array string.")); } - if (!JsonGetArray(list, jval) && required) { - return LogInfoError(cmStrCat(configKey, " is empty.")); + if (!GetJsonArray(list, jval) && required) { + return LogError(cmStrCat(configKey, " is empty.")); } return true; } } // Try plain - return InfoArray(key, list, required); + return GetArray(key, list, required); +} + +bool cmQtAutoGenerator::InfoT::LogError(GenT genType, + cm::string_view message) const +{ + Gen_.Log().Error(genType, + cmStrCat("Info error in info file\n", + Quoted(Gen_.InfoFile()), ":\n", message)); + return false; } -std::string cmQtAutoGenerator::SettingsFind(std::string const& content, - const char* key) +bool cmQtAutoGenerator::InfoT::LogError(cm::string_view message) const { - std::string prefix = cmStrCat(key, ':'); - std::string::size_type pos = content.find(prefix); - if (pos != std::string::npos) { + return LogError(Gen_.GenType_, message); +} + +std::string cmQtAutoGenerator::SettingsFind(cm::string_view content, + cm::string_view key) +{ + cm::string_view res; + std::string const prefix = cmStrCat(key, ':'); + cm::string_view::size_type pos = content.find(prefix); + if (pos != cm::string_view::npos) { pos += prefix.size(); if (pos < content.size()) { - std::string::size_type posE = content.find('\n', pos); - if ((posE != std::string::npos) && (posE != pos)) { - return content.substr(pos, posE - pos); + cm::string_view::size_type posE = content.find('\n', pos); + if ((posE != cm::string_view::npos) && (posE != pos)) { + res = content.substr(pos, posE - pos); } } } - return std::string(); + return std::string(res); } std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const @@ -470,3 +425,66 @@ std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const } return cmQtAutoGen::Quoted(res); } + +bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config) +{ + // Info config + InfoConfig_ = std::string(config); + + // Info file + InfoFile_ = std::string(infoFile); + cmSystemTools::CollapseFullPath(InfoFile_); + InfoDir_ = cmSystemTools::GetFilenamePath(InfoFile_); + + // Load info file time + if (!InfoFileTime_.Load(InfoFile_)) { + cmSystemTools::Stderr(cmStrCat("AutoGen: The info file ", + Quoted(InfoFile_), " is not readable\n")); + return false; + } + + { + InfoT info(*this); + + // Read info file + { + cmsys::ifstream ifs(InfoFile_.c_str(), + (std::ios::in | std::ios::binary)); + if (!ifs) { + Log().Error( + GenType_, + cmStrCat("Could not to open info file ", Quoted(InfoFile_))); + return false; + } + if (!info.Read(ifs)) { + Log().Error(GenType_, + cmStrCat("Could not read info file ", Quoted(InfoFile_))); + return false; + } + } + + // -- Read common info settings + { + unsigned int verbosity = 0; + // Info: setup project directories + if (!info.GetUInt("VERBOSITY", verbosity, false) || + !info.GetString("CMAKE_SOURCE_DIR", ProjectDirs_.Source, true) || + !info.GetString("CMAKE_BINARY_DIR", ProjectDirs_.Binary, true) || + !info.GetString("CMAKE_CURRENT_SOURCE_DIR", + ProjectDirs_.CurrentSource, true) || + !info.GetString("CMAKE_CURRENT_BINARY_DIR", + ProjectDirs_.CurrentBinary, true)) { + return false; + } + Logger_.RaiseVerbosity(verbosity); + } + + // -- Call virtual init from info method. + if (!this->InitFromInfo(info)) { + return false; + } + } + + // Call virtual process method. + return this->Process(); +} diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 7f83fc6..71ee9ce 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -11,6 +11,7 @@ #include <cm/string_view> +#include <istream> #include <mutex> #include <string> #include <unordered_set> @@ -86,54 +87,78 @@ public: cmQtAutoGenerator(cmQtAutoGenerator const&) = delete; cmQtAutoGenerator& operator=(cmQtAutoGenerator const&) = delete; - // -- Run - bool Run(std::string const& infoFile, std::string const& config); - - // -- InfoFile + // -- Info options std::string const& InfoFile() const { return InfoFile_; } - Json::Value const& Info() const { return Info_; } - cmFileTime const& InfoFileTime() const { return InfoFileTime_; } std::string const& InfoDir() const { return InfoDir_; } + cmFileTime const& InfoFileTime() const { return InfoFileTime_; } std::string const& InfoConfig() const { return InfoConfig_; } - bool LogInfoError(GenT genType, cm::string_view message) const; - bool LogInfoError(cm::string_view message) const; + // -- Info file parsing + /** Info file reader class. */ + class InfoT + { + public: + InfoT(cmQtAutoGenerator& gen) + : Gen_(gen) + { + } + + /** Read json data from a stream. */ + bool Read(std::istream& istr); + + /** Returns false if the JSON value isn't a string. */ + bool GetString(std::string const& key, std::string& value, + bool required) const; + bool GetStringConfig(std::string const& key, std::string& value, + bool required) const; + bool GetBool(std::string const& key, bool& value, bool required) const; + bool GetUInt(std::string const& key, unsigned int& value, + bool required) const; + /** Returns false if the JSON value isn't an array. */ + bool GetArray(std::string const& key, std::vector<std::string>& list, + bool required) const; + bool GetArray(std::string const& key, + std::unordered_set<std::string>& list, bool required) const; + bool GetArrayConfig(std::string const& key, std::vector<std::string>& list, + bool required) const; - /** Returns true if strings were appended to the list. */ - static bool JsonGetArray(std::vector<std::string>& list, - Json::Value const& jval); - /** Returns true if strings were found in the JSON array. */ - static bool JsonGetArray(std::unordered_set<std::string>& list, - Json::Value const& jval); + Json::Value const& GetValue(std::string const& key) const + { + return Json_[key]; + } - std::string InfoConfigKey(std::string const& key) const; + /** Returns true if strings were appended to the list. */ + static bool GetJsonArray(std::vector<std::string>& list, + Json::Value const& jval); + /** Returns true if strings were found in the JSON array. */ + static bool GetJsonArray(std::unordered_set<std::string>& list, + Json::Value const& jval); - /** Returns false if the JSON value isn't a string. */ - bool InfoString(std::string const& key, std::string& value, - bool required) const; - bool InfoStringConfig(std::string const& key, std::string& value, - bool required) const; - bool InfoBool(std::string const& key, bool& value, bool required) const; - bool InfoUInt(std::string const& key, unsigned int& value, - bool required) const; - /** Returns false if the JSON value isn't an array. */ - bool InfoArray(std::string const& key, std::vector<std::string>& list, - bool required) const; - bool InfoArray(std::string const& key, std::unordered_set<std::string>& list, - bool required) const; - bool InfoArrayConfig(std::string const& key, std::vector<std::string>& list, - bool required) const; + bool LogError(GenT genType, cm::string_view message) const; + bool LogError(cm::string_view message) const; + + private: + std::string ConfigKey(cm::string_view key) const; + + private: + Json::Value Json_; + cmQtAutoGenerator& Gen_; + }; + + // -- Settings file + static std::string SettingsFind(cm::string_view content, + cm::string_view key); // -- Directories ProjectDirsT const& ProjectDirs() const { return ProjectDirs_; } - - // -- Utility - static std::string SettingsFind(std::string const& content, const char* key); std::string MessagePath(cm::string_view path) const; + // -- Run + bool Run(cm::string_view infoFile, cm::string_view config); + protected: // -- Abstract processing interface - virtual bool InitFromInfo() = 0; + virtual bool InitFromInfo(InfoT const& info) = 0; virtual bool Process() = 0; // - Utility classes Logger const& Log() const { return Logger_; } @@ -145,10 +170,9 @@ private: Logger Logger_; // -- Info file std::string InfoFile_; - cmFileTime InfoFileTime_; std::string InfoDir_; + cmFileTime InfoFileTime_; std::string InfoConfig_; - Json::Value Info_; // -- Directories ProjectDirsT ProjectDirs_; }; diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 5f3cd5f..3b0f717 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -2,20 +2,33 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoMocUic.h" -#include <algorithm> -#include <set> -#include <utility> - -#include <cm/memory> - #include "cmAlgorithms.h" #include "cmCryptoHash.h" +#include "cmFileTime.h" #include "cmGeneratedFileStream.h" #include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cmWorkerPool.h" #include "cm_jsoncpp_value.h" #include "cmsys/FStream.hxx" +#include "cmsys/RegularExpression.hxx" + +#include <cm/memory> +#include <cm/string_view> + +#include <algorithm> +#include <atomic> +#include <cstddef> +#include <map> +#include <mutex> +#include <set> +#include <string> +#include <unordered_map> +#include <unordered_set> +#include <utility> +#include <vector> #if defined(__APPLE__) # include <unistd.h> @@ -26,10 +39,533 @@ namespace { constexpr std::size_t MocUnderscoreLength = 4; // Length of "moc_" constexpr std::size_t UiUnderscoreLength = 3; // Length of "ui_" -} // End of unnamed namespace +/** \class cmQtAutoMocUicT + * \brief AUTOMOC and AUTOUIC generator + */ +class cmQtAutoMocUicT : public cmQtAutoGenerator +{ +public: + cmQtAutoMocUicT(); + ~cmQtAutoMocUicT() override; + + cmQtAutoMocUicT(cmQtAutoMocUicT const&) = delete; + cmQtAutoMocUicT& operator=(cmQtAutoMocUicT const&) = delete; + +public: + // -- Types + + /** Include string with sub parts. */ + struct IncludeKeyT + { + IncludeKeyT(std::string const& key, std::size_t basePrefixLength); + + std::string Key; // Full include string + std::string Dir; // Include directory + std::string Base; // Base part of the include file name + }; + + /** Search key plus regular expression pair. */ + struct KeyExpT + { + KeyExpT(std::string key, std::string const& exp) + : Key(std::move(key)) + , Exp(exp) + { + } + + std::string Key; + cmsys::RegularExpression Exp; + }; + + /** Source file parsing cache. */ + class ParseCacheT + { + public: + // -- Types + + /** Entry of the file parsing cache. */ + struct FileT + { + void Clear(); + + struct MocT + { + std::string Macro; + struct IncludeT + { + std::vector<IncludeKeyT> Underscore; + std::vector<IncludeKeyT> Dot; + } Include; + std::vector<std::string> Depends; + } Moc; + + struct UicT + { + std::vector<IncludeKeyT> Include; + std::vector<std::string> Depends; + } Uic; + }; + using FileHandleT = std::shared_ptr<FileT>; + using GetOrInsertT = std::pair<FileHandleT, bool>; + + public: + ParseCacheT(); + ~ParseCacheT(); + + bool ReadFromFile(std::string const& fileName); + bool WriteToFile(std::string const& fileName); + + //! Always returns a valid handle + GetOrInsertT GetOrInsert(std::string const& fileName); + + private: + std::unordered_map<std::string, FileHandleT> Map_; + }; + + /** Source file data. */ + class SourceFileT + { + public: + SourceFileT(std::string fileName) + : FileName(std::move(fileName)) + { + } + + public: + std::string FileName; + cmFileTime FileTime; + ParseCacheT::FileHandleT ParseData; + std::string BuildPath; + bool IsHeader = false; + bool Moc = false; + bool Uic = false; + }; + using SourceFileHandleT = std::shared_ptr<SourceFileT>; + using SourceFileMapT = std::map<std::string, SourceFileHandleT>; + + /** Meta compiler file mapping information. */ + struct MappingT + { + SourceFileHandleT SourceFile; + std::string OutputFile; + std::string IncludeString; + std::vector<SourceFileHandleT> IncluderFiles; + }; + using MappingHandleT = std::shared_ptr<MappingT>; + using MappingMapT = std::map<std::string, MappingHandleT>; + + /** Common settings. */ + class BaseSettingsT + { + public: + // -- Constructors + BaseSettingsT(); + ~BaseSettingsT(); + + BaseSettingsT(BaseSettingsT const&) = delete; + BaseSettingsT& operator=(BaseSettingsT const&) = delete; + + // -- Attributes + // - Config + bool MultiConfig = false; + unsigned int QtVersionMajor = 4; + unsigned int ThreadCount = 0; + // - Directories + std::string AutogenBuildDir; + std::string AutogenIncludeDir; + // - Files + std::string CMakeExecutable; + cmFileTime CMakeExecutableTime; + std::string ParseCacheFile; + std::vector<std::string> HeaderExtensions; + }; + + /** Shared common variables. */ + class BaseEvalT + { + public: + // -- Parse Cache + bool ParseCacheChanged = false; + cmFileTime ParseCacheTime; + ParseCacheT ParseCache; + + // -- Sources + SourceFileMapT Headers; + SourceFileMapT Sources; + }; + + /** Moc settings. */ + class MocSettingsT + { + public: + // -- Constructors + MocSettingsT(); + ~MocSettingsT(); + + MocSettingsT(MocSettingsT const&) = delete; + MocSettingsT& operator=(MocSettingsT const&) = delete; + + // -- Const methods + bool skipped(std::string const& fileName) const; + std::string MacrosString() const; + + // -- Attributes + bool Enabled = false; + bool SettingsChanged = false; + bool RelaxedMode = false; + bool PathPrefix = false; + cmFileTime ExecutableTime; + std::string Executable; + std::string CompFileAbs; + std::string PredefsFileAbs; + std::unordered_set<std::string> SkipList; + std::vector<std::string> IncludePaths; + std::vector<std::string> Definitions; + std::vector<std::string> OptionsIncludes; + std::vector<std::string> OptionsDefinitions; + std::vector<std::string> OptionsExtra; + std::vector<std::string> PredefsCmd; + std::vector<KeyExpT> DependFilters; + std::vector<KeyExpT> MacroFilters; + cmsys::RegularExpression RegExpInclude; + }; + + /** Moc shared variables. */ + class MocEvalT + { + public: + // -- predefines file + cmFileTime PredefsTime; + // -- Mappings + MappingMapT HeaderMappings; + MappingMapT SourceMappings; + MappingMapT Includes; + // -- Discovered files + SourceFileMapT HeadersDiscovered; + // -- Output directories + std::unordered_set<std::string> OutputDirs; + // -- Mocs compilation + bool CompUpdated = false; + std::vector<std::string> CompFiles; + }; + + /** Uic settings. */ + class UicSettingsT + { + public: + struct UiFile + { + std::vector<std::string> Options; + }; + + public: + UicSettingsT(); + ~UicSettingsT(); + + UicSettingsT(UicSettingsT const&) = delete; + UicSettingsT& operator=(UicSettingsT const&) = delete; + + // -- Const methods + bool skipped(std::string const& fileName) const; + + // -- Attributes + bool Enabled = false; + bool SettingsChanged = false; + cmFileTime ExecutableTime; + std::string Executable; + std::unordered_set<std::string> SkipList; + std::vector<std::string> Options; + std::unordered_map<std::string, UiFile> UiFiles; + std::vector<std::string> SearchPaths; + cmsys::RegularExpression RegExpInclude; + }; + + /** Uic shared variables. */ + class UicEvalT + { + public: + // -- Discovered files + SourceFileMapT UiFiles; + // -- Mappings + MappingMapT Includes; + // -- Output directories + std::unordered_set<std::string> OutputDirs; + }; + + /** Abstract job class for concurrent job processing. */ + class JobT : public cmWorkerPool::JobT + { + protected: + /** Protected default constructor. */ + JobT(bool fence = false) + : cmWorkerPool::JobT(fence) + { + } + + //! Get the generator. Only valid during Process() call! + cmQtAutoMocUicT* Gen() const + { + return static_cast<cmQtAutoMocUicT*>(UserData()); + }; + + // -- Accessors. Only valid during Process() call! + Logger const& Log() const { return Gen()->Log(); } + BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); } + BaseEvalT& BaseEval() const { return Gen()->BaseEval(); } + MocSettingsT const& MocConst() const { return Gen()->MocConst(); } + MocEvalT& MocEval() const { return Gen()->MocEval(); } + UicSettingsT const& UicConst() const { return Gen()->UicConst(); } + UicEvalT& UicEval() const { return Gen()->UicEval(); } + + // -- Logging + std::string MessagePath(cm::string_view path) const + { + return Gen()->MessagePath(path); + } + // - Error logging with automatic abort + void LogError(GenT genType, cm::string_view message) const; + void LogCommandError(GenT genType, cm::string_view message, + std::vector<std::string> const& command, + std::string const& output) const; + + /** @brief Run an external process. Use only during Process() call! */ + bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, + std::vector<std::string> const& command, + std::string* infoMessage = nullptr); + }; + + /** Fence job utility class. */ + class JobFenceT : public JobT + { + public: + JobFenceT() + : JobT(true) + { + } + void Process() override{}; + }; + + /** Generate moc_predefs.h. */ + class JobMocPredefsT : public JobFenceT + { + void Process() override; + bool Update(std::string* reason) const; + }; + + /** File parse job base class. */ + class JobParseT : public JobT + { + public: + JobParseT(SourceFileHandleT fileHandle) + : FileHandle(std::move(fileHandle)) + { + } + + protected: + bool ReadFile(); + void CreateKeys(std::vector<IncludeKeyT>& container, + std::set<std::string> const& source, + std::size_t basePrefixLength); + void MocMacro(); + void MocDependecies(); + void MocIncludes(); + void UicIncludes(); + + protected: + SourceFileHandleT FileHandle; + std::string Content; + }; + + /** Header file parse job. */ + class JobParseHeaderT : public JobParseT + { + public: + using JobParseT::JobParseT; + void Process() override; + }; + + /** Source file parse job. */ + class JobParseSourceT : public JobParseT + { + public: + using JobParseT::JobParseT; + void Process() override; + }; + + /** Evaluate cached file parse data - moc. */ + class JobEvalCacheT : public JobT + { + protected: + std::string MessageSearchLocations() const; + std::vector<std::string> SearchLocations; + }; + + /** Evaluate cached file parse data - moc. */ + class JobEvalCacheMocT : public JobEvalCacheT + { + void Process() override; + bool EvalHeader(SourceFileHandleT source); + bool EvalSource(SourceFileHandleT const& source); + bool FindIncludedHeader(SourceFileHandleT& headerHandle, + cm::string_view includerDir, + cm::string_view includeBase); + bool RegisterIncluded(std::string const& includeString, + SourceFileHandleT includerFileHandle, + SourceFileHandleT sourceFileHandle) const; + void RegisterMapping(MappingHandleT mappingHandle) const; + std::string MessageHeader(cm::string_view headerBase) const; + }; + + /** Evaluate cached file parse data - uic. */ + class JobEvalCacheUicT : public JobEvalCacheT + { + void Process() override; + bool EvalFile(SourceFileHandleT const& sourceFileHandle); + bool FindIncludedUi(cm::string_view sourceDirPrefix, + cm::string_view includePrefix); + bool RegisterMapping(std::string const& includeString, + SourceFileHandleT includerFileHandle); + + std::string UiName; + SourceFileHandleT UiFileHandle; + }; + + /** Evaluate cached file parse data - finish */ + class JobEvalCacheFinishT : public JobFenceT + { + void Process() override; + }; + + /** Dependency probing base job. */ + class JobProbeDepsT : public JobT + { + }; + + /** Probes file dependencies and generates moc compile jobs. */ + class JobProbeDepsMocT : public JobProbeDepsT + { + void Process() override; + bool Generate(MappingHandleT const& mapping, bool compFile) const; + bool Probe(MappingT const& mapping, std::string* reason) const; + std::pair<std::string, cmFileTime> FindDependency( + std::string const& sourceDir, std::string const& includeString) const; + }; + + /** Probes file dependencies and generates uic compile jobs. */ + class JobProbeDepsUicT : public JobProbeDepsT + { + void Process() override; + bool Probe(MappingT const& mapping, std::string* reason) const; + }; + + /** Dependency probing finish job. */ + class JobProbeDepsFinishT : public JobFenceT + { + void Process() override; + }; + + /** Meta compiler base job. */ + class JobCompileT : public JobT + { + public: + JobCompileT(MappingHandleT uicMapping, std::unique_ptr<std::string> reason) + : Mapping(std::move(uicMapping)) + , Reason(std::move(reason)) + { + } + + protected: + MappingHandleT Mapping; + std::unique_ptr<std::string> Reason; + }; + + /** moc compiles a file. */ + class JobCompileMocT : public JobCompileT + { + public: + using JobCompileT::JobCompileT; + void Process() override; + }; -cmQtAutoMocUic::IncludeKeyT::IncludeKeyT(std::string const& key, - std::size_t basePrefixLength) + /** uic compiles a file. */ + class JobCompileUicT : public JobCompileT + { + public: + using JobCompileT::JobCompileT; + void Process() override; + }; + + /** Generate mocs_compilation.cpp. */ + class JobMocsCompilationT : public JobFenceT + { + private: + void Process() override; + }; + + /** @brief The last job. */ + class JobFinishT : public JobFenceT + { + private: + void Process() override; + }; + + // -- Const settings interface + BaseSettingsT const& BaseConst() const { return this->BaseConst_; } + BaseEvalT& BaseEval() { return this->BaseEval_; } + MocSettingsT const& MocConst() const { return this->MocConst_; } + MocEvalT& MocEval() { return this->MocEval_; } + UicSettingsT const& UicConst() const { return this->UicConst_; } + UicEvalT& UicEval() { return this->UicEval_; } + + // -- Parallel job processing interface + cmWorkerPool& WorkerPool() { return WorkerPool_; } + void AbortError() { Abort(true); } + void AbortSuccess() { Abort(false); } + + // -- Utility + std::string AbsoluteBuildPath(cm::string_view relativePath) const; + std::string AbsoluteIncludePath(cm::string_view relativePath) const; + template <class JOBTYPE> + void CreateParseJobs(SourceFileMapT const& sourceMap); + std::string CollapseFullPathTS(std::string const& path) const; + +private: + // -- Abstract processing interface + bool InitFromInfo(InfoT const& info) override; + void InitJobs(); + bool Process() override; + // -- Settings file + void SettingsFileRead(); + bool SettingsFileWrite(); + // -- Parse cache + void ParseCacheRead(); + bool ParseCacheWrite(); + // -- Thread processing + void Abort(bool error); + // -- Generation + bool CreateDirectories(); + +private: + // -- Settings + BaseSettingsT BaseConst_; + BaseEvalT BaseEval_; + MocSettingsT MocConst_; + MocEvalT MocEval_; + UicSettingsT UicConst_; + UicEvalT UicEval_; + // -- Settings file + std::string SettingsFile_; + std::string SettingsStringMoc_; + std::string SettingsStringUic_; + // -- Worker thread pool + std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false); + cmWorkerPool WorkerPool_; + // -- Concurrent processing + mutable std::mutex CMakeLibMutex_; +}; + +cmQtAutoMocUicT::IncludeKeyT::IncludeKeyT(std::string const& key, + std::size_t basePrefixLength) : Key(key) , Dir(SubDirPrefix(key)) , Base(cmSystemTools::GetFilenameWithoutLastExtension(key)) @@ -39,7 +575,7 @@ cmQtAutoMocUic::IncludeKeyT::IncludeKeyT(std::string const& key, } } -void cmQtAutoMocUic::ParseCacheT::FileT::Clear() +void cmQtAutoMocUicT::ParseCacheT::FileT::Clear() { Moc.Macro.clear(); Moc.Include.Underscore.clear(); @@ -50,18 +586,8 @@ void cmQtAutoMocUic::ParseCacheT::FileT::Clear() Uic.Depends.clear(); } -cmQtAutoMocUic::ParseCacheT::FileHandleT cmQtAutoMocUic::ParseCacheT::Get( - std::string const& fileName) const -{ - auto it = Map_.find(fileName); - if (it != Map_.end()) { - return it->second; - } - return FileHandleT(); -} - -cmQtAutoMocUic::ParseCacheT::GetOrInsertT -cmQtAutoMocUic::ParseCacheT::GetOrInsert(std::string const& fileName) +cmQtAutoMocUicT::ParseCacheT::GetOrInsertT +cmQtAutoMocUicT::ParseCacheT::GetOrInsert(std::string const& fileName) { // Find existing entry { @@ -77,15 +603,10 @@ cmQtAutoMocUic::ParseCacheT::GetOrInsert(std::string const& fileName) }; } -cmQtAutoMocUic::ParseCacheT::ParseCacheT() = default; -cmQtAutoMocUic::ParseCacheT::~ParseCacheT() = default; +cmQtAutoMocUicT::ParseCacheT::ParseCacheT() = default; +cmQtAutoMocUicT::ParseCacheT::~ParseCacheT() = default; -void cmQtAutoMocUic::ParseCacheT::Clear() -{ - Map_.clear(); -} - -bool cmQtAutoMocUic::ParseCacheT::ReadFromFile(std::string const& fileName) +bool cmQtAutoMocUicT::ParseCacheT::ReadFromFile(std::string const& fileName) { cmsys::ifstream fin(fileName.c_str()); if (!fin) { @@ -148,7 +669,7 @@ bool cmQtAutoMocUic::ParseCacheT::ReadFromFile(std::string const& fileName) return true; } -bool cmQtAutoMocUic::ParseCacheT::WriteToFile(std::string const& fileName) +bool cmQtAutoMocUicT::ParseCacheT::WriteToFile(std::string const& fileName) { cmGeneratedFileStream ofs(fileName); if (!ofs) { @@ -180,24 +701,24 @@ bool cmQtAutoMocUic::ParseCacheT::WriteToFile(std::string const& fileName) return ofs.Close(); } -cmQtAutoMocUic::BaseSettingsT::BaseSettingsT() = default; -cmQtAutoMocUic::BaseSettingsT::~BaseSettingsT() = default; +cmQtAutoMocUicT::BaseSettingsT::BaseSettingsT() = default; +cmQtAutoMocUicT::BaseSettingsT::~BaseSettingsT() = default; -cmQtAutoMocUic::MocSettingsT::MocSettingsT() +cmQtAutoMocUicT::MocSettingsT::MocSettingsT() { RegExpInclude.compile( "(^|\n)[ \t]*#[ \t]*include[ \t]+" "[\"<](([^ \">]+/)?moc_[^ \">/]+\\.cpp|[^ \">]+\\.moc)[\">]"); } -cmQtAutoMocUic::MocSettingsT::~MocSettingsT() = default; +cmQtAutoMocUicT::MocSettingsT::~MocSettingsT() = default; -bool cmQtAutoMocUic::MocSettingsT::skipped(std::string const& fileName) const +bool cmQtAutoMocUicT::MocSettingsT::skipped(std::string const& fileName) const { return (!Enabled || (SkipList.find(fileName) != SkipList.end())); } -std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const +std::string cmQtAutoMocUicT::MocSettingsT::MacrosString() const { std::string res; const auto itB = MacroFilters.cbegin(); @@ -219,27 +740,27 @@ std::string cmQtAutoMocUic::MocSettingsT::MacrosString() const return res; } -cmQtAutoMocUic::UicSettingsT::UicSettingsT() +cmQtAutoMocUicT::UicSettingsT::UicSettingsT() { RegExpInclude.compile("(^|\n)[ \t]*#[ \t]*include[ \t]+" "[\"<](([^ \">]+/)?ui_[^ \">/]+\\.h)[\">]"); } -cmQtAutoMocUic::UicSettingsT::~UicSettingsT() = default; +cmQtAutoMocUicT::UicSettingsT::~UicSettingsT() = default; -bool cmQtAutoMocUic::UicSettingsT::skipped(std::string const& fileName) const +bool cmQtAutoMocUicT::UicSettingsT::skipped(std::string const& fileName) const { return (!Enabled || (SkipList.find(fileName) != SkipList.end())); } -void cmQtAutoMocUic::JobT::LogError(GenT genType, - cm::string_view message) const +void cmQtAutoMocUicT::JobT::LogError(GenT genType, + cm::string_view message) const { Gen()->AbortError(); Gen()->Log().Error(genType, message); } -void cmQtAutoMocUic::JobT::LogCommandError( +void cmQtAutoMocUicT::JobT::LogCommandError( GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const { @@ -247,10 +768,10 @@ void cmQtAutoMocUic::JobT::LogCommandError( Gen()->Log().ErrorCommand(genType, message, command, output); } -bool cmQtAutoMocUic::JobT::RunProcess(GenT genType, - cmWorkerPool::ProcessResultT& result, - std::vector<std::string> const& command, - std::string* infoMessage) +bool cmQtAutoMocUicT::JobT::RunProcess(GenT genType, + cmWorkerPool::ProcessResultT& result, + std::vector<std::string> const& command, + std::string* infoMessage) { // Log command if (Log().Verbose()) { @@ -268,7 +789,7 @@ bool cmQtAutoMocUic::JobT::RunProcess(GenT genType, BaseConst().AutogenBuildDir); } -void cmQtAutoMocUic::JobMocPredefsT::Process() +void cmQtAutoMocUicT::JobMocPredefsT::Process() { // (Re)generate moc_predefs.h on demand std::unique_ptr<std::string> reason; @@ -330,7 +851,7 @@ void cmQtAutoMocUic::JobMocPredefsT::Process() } } -bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const +bool cmQtAutoMocUicT::JobMocPredefsT::Update(std::string* reason) const { // Test if the file exists if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) { @@ -369,7 +890,7 @@ bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const return false; } -bool cmQtAutoMocUic::JobParseT::ReadFile() +bool cmQtAutoMocUicT::JobParseT::ReadFile() { // Clear old parse information FileHandle->ParseData->Clear(); @@ -396,9 +917,9 @@ bool cmQtAutoMocUic::JobParseT::ReadFile() return true; } -void cmQtAutoMocUic::JobParseT::CreateKeys(std::vector<IncludeKeyT>& container, - std::set<std::string> const& source, - std::size_t basePrefixLength) +void cmQtAutoMocUicT::JobParseT::CreateKeys( + std::vector<IncludeKeyT>& container, std::set<std::string> const& source, + std::size_t basePrefixLength) { if (source.empty()) { return; @@ -409,7 +930,7 @@ void cmQtAutoMocUic::JobParseT::CreateKeys(std::vector<IncludeKeyT>& container, } } -void cmQtAutoMocUic::JobParseT::MocMacro() +void cmQtAutoMocUicT::JobParseT::MocMacro() { for (KeyExpT const& filter : MocConst().MacroFilters) { // Run a simple find string check @@ -426,7 +947,7 @@ void cmQtAutoMocUic::JobParseT::MocMacro() } } -void cmQtAutoMocUic::JobParseT::MocDependecies() +void cmQtAutoMocUicT::JobParseT::MocDependecies() { if (MocConst().DependFilters.empty()) { return; @@ -467,7 +988,7 @@ void cmQtAutoMocUic::JobParseT::MocDependecies() } } -void cmQtAutoMocUic::JobParseT::MocIncludes() +void cmQtAutoMocUicT::JobParseT::MocIncludes() { if (Content.find("moc") == std::string::npos) { return; @@ -500,7 +1021,7 @@ void cmQtAutoMocUic::JobParseT::MocIncludes() CreateKeys(Include.Dot, dot, 0); } -void cmQtAutoMocUic::JobParseT::UicIncludes() +void cmQtAutoMocUicT::JobParseT::UicIncludes() { if (Content.find("ui_") == std::string::npos) { return; @@ -520,7 +1041,7 @@ void cmQtAutoMocUic::JobParseT::UicIncludes() CreateKeys(FileHandle->ParseData->Uic.Include, includes, UiUnderscoreLength); } -void cmQtAutoMocUic::JobParseHeaderT::Process() +void cmQtAutoMocUicT::JobParseHeaderT::Process() { if (!ReadFile()) { return; @@ -536,7 +1057,7 @@ void cmQtAutoMocUic::JobParseHeaderT::Process() } } -void cmQtAutoMocUic::JobParseSourceT::Process() +void cmQtAutoMocUicT::JobParseSourceT::Process() { if (!ReadFile()) { return; @@ -553,7 +1074,7 @@ void cmQtAutoMocUic::JobParseSourceT::Process() } } -std::string cmQtAutoMocUic::JobEvalCacheT::MessageSearchLocations() const +std::string cmQtAutoMocUicT::JobEvalCacheT::MessageSearchLocations() const { std::string res; res.reserve(512); @@ -565,7 +1086,7 @@ std::string cmQtAutoMocUic::JobEvalCacheT::MessageSearchLocations() const return res; } -void cmQtAutoMocUic::JobEvalCacheMocT::Process() +void cmQtAutoMocUicT::JobEvalCacheMocT::Process() { // Evaluate headers for (auto const& pair : BaseEval().Headers) { @@ -581,7 +1102,7 @@ void cmQtAutoMocUic::JobEvalCacheMocT::Process() } } -bool cmQtAutoMocUic::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source) +bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source) { SourceFileT const& sourceFile = *source; auto const& parseData = sourceFile.ParseData->Moc; @@ -608,7 +1129,7 @@ bool cmQtAutoMocUic::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source) return true; } -bool cmQtAutoMocUic::JobEvalCacheMocT::EvalSource( +bool cmQtAutoMocUicT::JobEvalCacheMocT::EvalSource( SourceFileHandleT const& source) { SourceFileT const& sourceFile = *source; @@ -809,7 +1330,7 @@ bool cmQtAutoMocUic::JobEvalCacheMocT::EvalSource( return true; } -bool cmQtAutoMocUic::JobEvalCacheMocT::FindIncludedHeader( +bool cmQtAutoMocUicT::JobEvalCacheMocT::FindIncludedHeader( SourceFileHandleT& headerHandle, cm::string_view includerDir, cm::string_view includeBase) { @@ -874,7 +1395,7 @@ bool cmQtAutoMocUic::JobEvalCacheMocT::FindIncludedHeader( return false; } -bool cmQtAutoMocUic::JobEvalCacheMocT::RegisterIncluded( +bool cmQtAutoMocUicT::JobEvalCacheMocT::RegisterIncluded( std::string const& includeString, SourceFileHandleT includerFileHandle, SourceFileHandleT sourceFileHandle) const { @@ -922,7 +1443,7 @@ bool cmQtAutoMocUic::JobEvalCacheMocT::RegisterIncluded( return true; } -void cmQtAutoMocUic::JobEvalCacheMocT::RegisterMapping( +void cmQtAutoMocUicT::JobEvalCacheMocT::RegisterMapping( MappingHandleT mappingHandle) const { auto& regMap = mappingHandle->SourceFile->IsHeader @@ -941,14 +1462,14 @@ void cmQtAutoMocUic::JobEvalCacheMocT::RegisterMapping( } } -std::string cmQtAutoMocUic::JobEvalCacheMocT::MessageHeader( +std::string cmQtAutoMocUicT::JobEvalCacheMocT::MessageHeader( cm::string_view headerBase) const { return MessagePath(cmStrCat( headerBase, ".{", cmJoin(this->BaseConst().HeaderExtensions, ","), '}')); } -void cmQtAutoMocUic::JobEvalCacheUicT::Process() +void cmQtAutoMocUicT::JobEvalCacheUicT::Process() { // Prepare buffers SearchLocations.reserve((UicConst().SearchPaths.size() + 1) * 2); @@ -967,7 +1488,7 @@ void cmQtAutoMocUic::JobEvalCacheUicT::Process() } } -bool cmQtAutoMocUic::JobEvalCacheUicT::EvalFile( +bool cmQtAutoMocUicT::JobEvalCacheUicT::EvalFile( SourceFileHandleT const& sourceFileHandle) { SourceFileT const& sourceFile = *sourceFileHandle; @@ -1002,7 +1523,7 @@ bool cmQtAutoMocUic::JobEvalCacheUicT::EvalFile( return true; } -bool cmQtAutoMocUic::JobEvalCacheUicT::FindIncludedUi( +bool cmQtAutoMocUicT::JobEvalCacheUicT::FindIncludedUi( cm::string_view sourceDirPrefix, cm::string_view includePrefix) { // Clear locations buffer @@ -1056,7 +1577,7 @@ bool cmQtAutoMocUic::JobEvalCacheUicT::FindIncludedUi( return false; } -bool cmQtAutoMocUic::JobEvalCacheUicT::RegisterMapping( +bool cmQtAutoMocUicT::JobEvalCacheUicT::RegisterMapping( std::string const& includeString, SourceFileHandleT includerFileHandle) { auto& Includes = Gen()->UicEval().Includes; @@ -1101,7 +1622,7 @@ bool cmQtAutoMocUic::JobEvalCacheUicT::RegisterMapping( return true; } -void cmQtAutoMocUic::JobEvalCacheFinishT::Process() +void cmQtAutoMocUicT::JobEvalCacheFinishT::Process() { // Add discovered header parse jobs Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered); @@ -1121,7 +1642,7 @@ void cmQtAutoMocUic::JobEvalCacheFinishT::Process() } } -void cmQtAutoMocUic::JobProbeDepsMocT::Process() +void cmQtAutoMocUicT::JobProbeDepsMocT::Process() { // Create moc header jobs for (auto const& pair : MocEval().HeaderMappings) { @@ -1143,8 +1664,8 @@ void cmQtAutoMocUic::JobProbeDepsMocT::Process() } } -bool cmQtAutoMocUic::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, - bool compFile) const +bool cmQtAutoMocUicT::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, + bool compFile) const { std::unique_ptr<std::string> reason; if (Log().Verbose()) { @@ -1163,8 +1684,8 @@ bool cmQtAutoMocUic::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, return true; } -bool cmQtAutoMocUic::JobProbeDepsMocT::Probe(MappingT const& mapping, - std::string* reason) const +bool cmQtAutoMocUicT::JobProbeDepsMocT::Probe(MappingT const& mapping, + std::string* reason) const { std::string const& sourceFile = mapping.SourceFile->FileName; std::string const& outputFile = mapping.OutputFile; @@ -1254,7 +1775,7 @@ bool cmQtAutoMocUic::JobProbeDepsMocT::Probe(MappingT const& mapping, } std::pair<std::string, cmFileTime> -cmQtAutoMocUic::JobProbeDepsMocT::FindDependency( +cmQtAutoMocUicT::JobProbeDepsMocT::FindDependency( std::string const& sourceDir, std::string const& includeString) const { using ResPair = std::pair<std::string, cmFileTime>; @@ -1276,7 +1797,7 @@ cmQtAutoMocUic::JobProbeDepsMocT::FindDependency( return ResPair(); } -void cmQtAutoMocUic::JobProbeDepsUicT::Process() +void cmQtAutoMocUicT::JobProbeDepsUicT::Process() { for (auto const& pair : Gen()->UicEval().Includes) { MappingHandleT const& mapping = pair.second; @@ -1295,8 +1816,8 @@ void cmQtAutoMocUic::JobProbeDepsUicT::Process() } } -bool cmQtAutoMocUic::JobProbeDepsUicT::Probe(MappingT const& mapping, - std::string* reason) const +bool cmQtAutoMocUicT::JobProbeDepsUicT::Probe(MappingT const& mapping, + std::string* reason) const { std::string const& sourceFile = mapping.SourceFile->FileName; std::string const& outputFile = mapping.OutputFile; @@ -1345,7 +1866,7 @@ bool cmQtAutoMocUic::JobProbeDepsUicT::Probe(MappingT const& mapping, return false; } -void cmQtAutoMocUic::JobProbeDepsFinishT::Process() +void cmQtAutoMocUicT::JobProbeDepsFinishT::Process() { // Create output directories { @@ -1381,7 +1902,7 @@ void cmQtAutoMocUic::JobProbeDepsFinishT::Process() Gen()->WorkerPool().EmplaceJob<JobFinishT>(); } -void cmQtAutoMocUic::JobCompileMocT::Process() +void cmQtAutoMocUicT::JobCompileMocT::Process() { std::string const& sourceFile = Mapping->SourceFile->FileName; std::string const& outputFile = Mapping->OutputFile; @@ -1458,7 +1979,7 @@ void cmQtAutoMocUic::JobCompileMocT::Process() } } -void cmQtAutoMocUic::JobCompileUicT::Process() +void cmQtAutoMocUicT::JobCompileUicT::Process() { std::string const& sourceFile = Mapping->SourceFile->FileName; std::string const& outputFile = Mapping->OutputFile; @@ -1501,7 +2022,7 @@ void cmQtAutoMocUic::JobCompileUicT::Process() } } -void cmQtAutoMocUic::JobMocsCompilationT::Process() +void cmQtAutoMocUicT::JobMocsCompilationT::Process() { // Compose mocs compilation file content std::string content = @@ -1546,39 +2067,41 @@ void cmQtAutoMocUic::JobMocsCompilationT::Process() } } -void cmQtAutoMocUic::JobFinishT::Process() +void cmQtAutoMocUicT::JobFinishT::Process() { Gen()->AbortSuccess(); } -cmQtAutoMocUic::cmQtAutoMocUic() +cmQtAutoMocUicT::cmQtAutoMocUicT() : cmQtAutoGenerator(GenT::GEN) { } -cmQtAutoMocUic::~cmQtAutoMocUic() = default; +cmQtAutoMocUicT::~cmQtAutoMocUicT() = default; -bool cmQtAutoMocUic::InitFromInfo() +bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) { // -- Required settings - if (!InfoBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) || - !InfoUInt("QT_VERSION_MAJOR", BaseConst_.QtVersionMajor, true) || - !InfoUInt("PARALLEL", BaseConst_.ThreadCount, false) || - !InfoString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) || - !InfoStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir, true) || - !InfoString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) || - !InfoStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile, true) || - !InfoStringConfig("SETTINGS_FILE", SettingsFile_, true) || - !InfoArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || - !InfoString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || - !InfoString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) { + if (!info.GetBool("MULTI_CONFIG", BaseConst_.MultiConfig, true) || + !info.GetUInt("QT_VERSION_MAJOR", BaseConst_.QtVersionMajor, true) || + !info.GetUInt("PARALLEL", BaseConst_.ThreadCount, false) || + !info.GetString("BUILD_DIR", BaseConst_.AutogenBuildDir, true) || + !info.GetStringConfig("INCLUDE_DIR", BaseConst_.AutogenIncludeDir, + true) || + !info.GetString("CMAKE_EXECUTABLE", BaseConst_.CMakeExecutable, true) || + !info.GetStringConfig("PARSE_CACHE_FILE", BaseConst_.ParseCacheFile, + true) || + !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || + !info.GetArray("HEADER_EXTENSIONS", BaseConst_.HeaderExtensions, true) || + !info.GetString("QT_MOC_EXECUTABLE", MocConst_.Executable, false) || + !info.GetString("QT_UIC_EXECUTABLE", UicConst_.Executable, false)) { return false; } // -- Checks if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) { - return LogInfoError(cmStrCat("The CMake executable ", - MessagePath(BaseConst_.CMakeExecutable), - " does not exist.")); + return info.LogError(cmStrCat("The CMake executable ", + MessagePath(BaseConst_.CMakeExecutable), + " does not exist.")); } // -- Evaluate values @@ -1598,19 +2121,20 @@ bool cmQtAutoMocUic::InitFromInfo() } tmp; // -- Required settings - if (!InfoBool("MOC_RELAXED_MODE", MocConst_.RelaxedMode, false) || - !InfoBool("MOC_PATH_PREFIX", MocConst_.PathPrefix, true) || - !InfoArray("MOC_SKIP", MocConst_.SkipList, false) || - !InfoArrayConfig("MOC_DEFINITIONS", MocConst_.Definitions, false) || - !InfoArrayConfig("MOC_INCLUDES", MocConst_.IncludePaths, false) || - !InfoArray("MOC_OPTIONS", MocConst_.OptionsExtra, false) || - !InfoStringConfig("MOC_COMPILATION_FILE", MocConst_.CompFileAbs, - true) || - !InfoArray("MOC_PREDEFS_CMD", MocConst_.PredefsCmd, false) || - !InfoStringConfig("MOC_PREDEFS_FILE", MocConst_.PredefsFileAbs, - !MocConst_.PredefsCmd.empty()) || - !InfoArray("MOC_MACRO_NAMES", tmp.MacroNames, true) || - !InfoArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) { + if (!info.GetBool("MOC_RELAXED_MODE", MocConst_.RelaxedMode, false) || + !info.GetBool("MOC_PATH_PREFIX", MocConst_.PathPrefix, true) || + !info.GetArray("MOC_SKIP", MocConst_.SkipList, false) || + !info.GetArrayConfig("MOC_DEFINITIONS", MocConst_.Definitions, + false) || + !info.GetArrayConfig("MOC_INCLUDES", MocConst_.IncludePaths, false) || + !info.GetArray("MOC_OPTIONS", MocConst_.OptionsExtra, false) || + !info.GetStringConfig("MOC_COMPILATION_FILE", MocConst_.CompFileAbs, + true) || + !info.GetArray("MOC_PREDEFS_CMD", MocConst_.PredefsCmd, false) || + !info.GetStringConfig("MOC_PREDEFS_FILE", MocConst_.PredefsFileAbs, + !MocConst_.PredefsCmd.empty()) || + !info.GetArray("MOC_MACRO_NAMES", tmp.MacroNames, true) || + !info.GetArray("MOC_DEPEND_FILTERS", tmp.DependFilters, false)) { return false; } @@ -1621,18 +2145,17 @@ bool cmQtAutoMocUic::InitFromInfo() } // Dependency filters { - Json::Value const& val = Info()["MOC_DEPEND_FILTERS"]; + Json::Value const& val = info.GetValue("MOC_DEPEND_FILTERS"); if (!val.isArray()) { - return LogInfoError("MOC_DEPEND_FILTERS JSON value is not an array."); + return info.LogError("MOC_DEPEND_FILTERS JSON value is not an array."); } Json::ArrayIndex const arraySize = val.size(); for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) { // Test entry closure - auto testEntry = [this, ii](bool test, - cm::string_view message) -> bool { + auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool { if (!test) { - this->LogInfoError( - cmStrCat("MOC_DEPEND_FILTERS filter ", ii, ": ", message)); + info.LogError( + cmStrCat("MOC_DEPEND_FILTERS filter ", ii, ": ", msg)); } return !test; }; @@ -1671,9 +2194,9 @@ bool cmQtAutoMocUic::InitFromInfo() } // Check if moc executable exists (by reading the file time) if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) { - return LogInfoError(cmStrCat("The moc executable ", - MessagePath(MocConst_.Executable), - " does not exist.")); + return info.LogError(cmStrCat("The moc executable ", + MessagePath(MocConst_.Executable), + " does not exist.")); } } @@ -1683,25 +2206,23 @@ bool cmQtAutoMocUic::InitFromInfo() UicConst_.Enabled = true; // -- Required settings - if (!InfoArray("UIC_SKIP", UicConst_.SkipList, false) || - !InfoArray("UIC_SEARCH_PATHS", UicConst_.SearchPaths, false) || - !InfoArrayConfig("UIC_OPTIONS", UicConst_.Options, false)) { + if (!info.GetArray("UIC_SKIP", UicConst_.SkipList, false) || + !info.GetArray("UIC_SEARCH_PATHS", UicConst_.SearchPaths, false) || + !info.GetArrayConfig("UIC_OPTIONS", UicConst_.Options, false)) { return false; } // .ui files { - Json::Value const& val = Info()["UIC_UI_FILES"]; + Json::Value const& val = info.GetValue("UIC_UI_FILES"); if (!val.isArray()) { - return LogInfoError("UIC_UI_FILES JSON value is not an array."); + return info.LogError("UIC_UI_FILES JSON value is not an array."); } Json::ArrayIndex const arraySize = val.size(); for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) { // Test entry closure - auto testEntry = [this, ii](bool test, - cm::string_view message) -> bool { + auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool { if (!test) { - this->LogInfoError( - cmStrCat("UIC_UI_FILES entry ", ii, ": ", message)); + info.LogError(cmStrCat("UIC_UI_FILES entry ", ii, ": ", msg)); } return !test; }; @@ -1722,31 +2243,31 @@ bool cmQtAutoMocUic::InitFromInfo() } auto& uiFile = UicConst_.UiFiles[entryName.asString()]; - JsonGetArray(uiFile.Options, entryOptions); + InfoT::GetJsonArray(uiFile.Options, entryOptions); } } // -- Evaluate settings // Check if uic executable exists (by reading the file time) if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) { - return LogInfoError(cmStrCat("The uic executable ", - MessagePath(UicConst_.Executable), - " does not exist.")); + return info.LogError(cmStrCat("The uic executable ", + MessagePath(UicConst_.Executable), + " does not exist.")); } } // -- Headers { - Json::Value const& val = Info()["HEADERS"]; + Json::Value const& val = info.GetValue("HEADERS"); if (!val.isArray()) { - return LogInfoError("HEADERS JSON value is not an array."); + return info.LogError("HEADERS JSON value is not an array."); } Json::ArrayIndex const arraySize = val.size(); for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) { // Test entry closure - auto testEntry = [this, ii](bool test, cm::string_view message) -> bool { + auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool { if (!test) { - this->LogInfoError(cmStrCat("HEADERS entry ", ii, ": ", message)); + info.LogError(cmStrCat("HEADERS entry ", ii, ": ", msg)); } return !test; }; @@ -1778,9 +2299,8 @@ bool cmQtAutoMocUic::InitFromInfo() cmFileTime fileTime; if (!fileTime.Load(name)) { - LogInfoError(cmStrCat("The header file ", this->MessagePath(name), - " does not exist.")); - return false; + return info.LogError(cmStrCat( + "The header file ", this->MessagePath(name), " does not exist.")); } SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name); @@ -1790,7 +2310,7 @@ bool cmQtAutoMocUic::InitFromInfo() sourceHandle->Uic = (flags[1] == 'U'); if (sourceHandle->Moc && MocConst().Enabled) { if (build.empty()) { - return LogInfoError( + return info.LogError( cmStrCat("Header file ", ii, " build path is empty")); } sourceHandle->BuildPath = std::move(build); @@ -1801,16 +2321,16 @@ bool cmQtAutoMocUic::InitFromInfo() // -- Sources { - Json::Value const& val = Info()["SOURCES"]; + Json::Value const& val = info.GetValue("SOURCES"); if (!val.isArray()) { - return LogInfoError("SOURCES JSON value is not an array."); + return info.LogError("SOURCES JSON value is not an array."); } Json::ArrayIndex const arraySize = val.size(); for (Json::ArrayIndex ii = 0; ii != arraySize; ++ii) { // Test entry closure - auto testEntry = [this, ii](bool test, cm::string_view message) -> bool { + auto testEntry = [&info, ii](bool test, cm::string_view msg) -> bool { if (!test) { - this->LogInfoError(cmStrCat("SOURCES entry ", ii, ": ", message)); + info.LogError(cmStrCat("SOURCES entry ", ii, ": ", msg)); } return !test; }; @@ -1838,9 +2358,8 @@ bool cmQtAutoMocUic::InitFromInfo() cmFileTime fileTime; if (!fileTime.Load(name)) { - LogInfoError(cmStrCat("The source file ", this->MessagePath(name), - " does not exist.")); - return false; + return info.LogError(cmStrCat( + "The source file ", this->MessagePath(name), " does not exist.")); } SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(name); @@ -1896,7 +2415,7 @@ bool cmQtAutoMocUic::InitFromInfo() } template <class JOBTYPE> -void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap) +void cmQtAutoMocUicT::CreateParseJobs(SourceFileMapT const& sourceMap) { cmFileTime const parseCacheTime = BaseEval().ParseCacheTime; ParseCacheT& parseCache = BaseEval().ParseCache; @@ -1913,13 +2432,13 @@ void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap) } /** Concurrently callable implementation of cmSystemTools::CollapseFullPath */ -std::string cmQtAutoMocUic::CollapseFullPathTS(std::string const& path) const +std::string cmQtAutoMocUicT::CollapseFullPathTS(std::string const& path) const { std::lock_guard<std::mutex> guard(CMakeLibMutex_); return cmSystemTools::CollapseFullPath(path, ProjectDirs().CurrentSource); } -void cmQtAutoMocUic::InitJobs() +void cmQtAutoMocUicT::InitJobs() { // Add moc_predefs.h job if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) { @@ -1946,7 +2465,7 @@ void cmQtAutoMocUic::InitJobs() } } -bool cmQtAutoMocUic::Process() +bool cmQtAutoMocUicT::Process() { SettingsFileRead(); ParseCacheRead(); @@ -1969,7 +2488,7 @@ bool cmQtAutoMocUic::Process() return true; } -void cmQtAutoMocUic::SettingsFileRead() +void cmQtAutoMocUicT::SettingsFileRead() { // Compose current settings strings { @@ -2048,7 +2567,7 @@ void cmQtAutoMocUic::SettingsFileRead() } } -bool cmQtAutoMocUic::SettingsFileWrite() +bool cmQtAutoMocUicT::SettingsFileWrite() { // Only write if any setting changed if (MocConst().SettingsChanged || UicConst().SettingsChanged) { @@ -2083,7 +2602,7 @@ bool cmQtAutoMocUic::SettingsFileWrite() return true; } -void cmQtAutoMocUic::ParseCacheRead() +void cmQtAutoMocUicT::ParseCacheRead() { cm::string_view reason; // Don't read the cache if it is invalid @@ -2109,7 +2628,7 @@ void cmQtAutoMocUic::ParseCacheRead() } } -bool cmQtAutoMocUic::ParseCacheWrite() +bool cmQtAutoMocUicT::ParseCacheWrite() { if (BaseEval().ParseCacheChanged) { if (Log().Verbose()) { @@ -2128,7 +2647,7 @@ bool cmQtAutoMocUic::ParseCacheWrite() return true; } -bool cmQtAutoMocUic::CreateDirectories() +bool cmQtAutoMocUicT::CreateDirectories() { // Create AUTOGEN include directory if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) { @@ -2141,7 +2660,7 @@ bool cmQtAutoMocUic::CreateDirectories() return true; } -void cmQtAutoMocUic::Abort(bool error) +void cmQtAutoMocUicT::Abort(bool error) { if (error) { JobError_.store(true); @@ -2149,14 +2668,21 @@ void cmQtAutoMocUic::Abort(bool error) WorkerPool_.Abort(); } -std::string cmQtAutoMocUic::AbsoluteBuildPath( +std::string cmQtAutoMocUicT::AbsoluteBuildPath( cm::string_view relativePath) const { return cmStrCat(BaseConst().AutogenBuildDir, '/', relativePath); } -std::string cmQtAutoMocUic::AbsoluteIncludePath( +std::string cmQtAutoMocUicT::AbsoluteIncludePath( cm::string_view relativePath) const { return cmStrCat(BaseConst().AutogenIncludeDir, '/', relativePath); } + +} // End of unnamed namespace + +bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config) +{ + return cmQtAutoMocUicT().Run(infoFile, config); +} diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h index 7101b8f..ffcc2db 100644 --- a/Source/cmQtAutoMocUic.h +++ b/Source/cmQtAutoMocUic.h @@ -5,555 +5,12 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmFileTime.h" -#include "cmQtAutoGen.h" -#include "cmQtAutoGenerator.h" -#include "cmWorkerPool.h" -#include "cmsys/RegularExpression.hxx" - #include <cm/string_view> -#include <atomic> -#include <cstddef> -#include <map> -#include <memory> -#include <mutex> -#include <set> -#include <string> -#include <unordered_map> -#include <unordered_set> -#include <utility> -#include <vector> - -/** \class cmQtAutoMocUic - * \brief AUTOMOC and AUTOUIC generator +/** + * Process AUTOMOC and AUTOUIC + * @return true on success */ -class cmQtAutoMocUic : public cmQtAutoGenerator -{ -public: - cmQtAutoMocUic(); - ~cmQtAutoMocUic() override; - - cmQtAutoMocUic(cmQtAutoMocUic const&) = delete; - cmQtAutoMocUic& operator=(cmQtAutoMocUic const&) = delete; - -public: - // -- Types - - /** Include string with sub parts. */ - struct IncludeKeyT - { - IncludeKeyT(std::string const& key, std::size_t basePrefixLength); - - std::string Key; // Full include string - std::string Dir; // Include directory - std::string Base; // Base part of the include file name - }; - - /** Search key plus regular expression pair. */ - struct KeyExpT - { - KeyExpT() = default; - - KeyExpT(std::string key, std::string const& exp) - : Key(std::move(key)) - , Exp(exp) - { - } - - std::string Key; - cmsys::RegularExpression Exp; - }; - - /** Source file parsing cache. */ - class ParseCacheT - { - public: - // -- Types - - /** Entry of the file parsing cache. */ - struct FileT - { - void Clear(); - - struct MocT - { - std::string Macro; - struct IncludeT - { - std::vector<IncludeKeyT> Underscore; - std::vector<IncludeKeyT> Dot; - } Include; - std::vector<std::string> Depends; - } Moc; - - struct UicT - { - std::vector<IncludeKeyT> Include; - std::vector<std::string> Depends; - } Uic; - }; - using FileHandleT = std::shared_ptr<FileT>; - using GetOrInsertT = std::pair<FileHandleT, bool>; - - public: - ParseCacheT(); - ~ParseCacheT(); - - void Clear(); - - bool ReadFromFile(std::string const& fileName); - bool WriteToFile(std::string const& fileName); - - //! Might return an invalid handle - FileHandleT Get(std::string const& fileName) const; - //! Always returns a valid handle - GetOrInsertT GetOrInsert(std::string const& fileName); - - private: - std::unordered_map<std::string, FileHandleT> Map_; - }; - - /** Source file data. */ - class SourceFileT - { - public: - SourceFileT(std::string fileName) - : FileName(std::move(fileName)) - { - } - - public: - std::string FileName; - cmFileTime FileTime; - ParseCacheT::FileHandleT ParseData; - std::string BuildPath; - bool IsHeader = false; - bool Moc = false; - bool Uic = false; - }; - using SourceFileHandleT = std::shared_ptr<SourceFileT>; - using SourceFileMapT = std::map<std::string, SourceFileHandleT>; - - /** Meta compiler file mapping information. */ - struct MappingT - { - SourceFileHandleT SourceFile; - std::string OutputFile; - std::string IncludeString; - std::vector<SourceFileHandleT> IncluderFiles; - }; - using MappingHandleT = std::shared_ptr<MappingT>; - using MappingMapT = std::map<std::string, MappingHandleT>; - - /** Common settings. */ - class BaseSettingsT - { - public: - // -- Constructors - BaseSettingsT(); - ~BaseSettingsT(); - - BaseSettingsT(BaseSettingsT const&) = delete; - BaseSettingsT& operator=(BaseSettingsT const&) = delete; - - // -- Attributes - // - Config - bool MultiConfig = false; - unsigned int QtVersionMajor = 4; - unsigned int ThreadCount = 0; - // - Directories - std::string AutogenBuildDir; - std::string AutogenIncludeDir; - // - Files - std::string CMakeExecutable; - cmFileTime CMakeExecutableTime; - std::string ParseCacheFile; - std::vector<std::string> HeaderExtensions; - }; - - /** Shared common variables. */ - class BaseEvalT - { - public: - // -- Parse Cache - bool ParseCacheChanged = false; - cmFileTime ParseCacheTime; - ParseCacheT ParseCache; - - // -- Sources - SourceFileMapT Headers; - SourceFileMapT Sources; - }; - - /** Moc settings. */ - class MocSettingsT - { - public: - // -- Constructors - MocSettingsT(); - ~MocSettingsT(); - - MocSettingsT(MocSettingsT const&) = delete; - MocSettingsT& operator=(MocSettingsT const&) = delete; - - // -- Const methods - bool skipped(std::string const& fileName) const; - std::string MacrosString() const; - - // -- Attributes - bool Enabled = false; - bool SettingsChanged = false; - bool RelaxedMode = false; - bool PathPrefix = false; - cmFileTime ExecutableTime; - std::string Executable; - std::string CompFileAbs; - std::string PredefsFileAbs; - std::unordered_set<std::string> SkipList; - std::vector<std::string> IncludePaths; - std::vector<std::string> Definitions; - std::vector<std::string> OptionsIncludes; - std::vector<std::string> OptionsDefinitions; - std::vector<std::string> OptionsExtra; - std::vector<std::string> PredefsCmd; - std::vector<KeyExpT> DependFilters; - std::vector<KeyExpT> MacroFilters; - cmsys::RegularExpression RegExpInclude; - }; - - /** Moc shared variables. */ - class MocEvalT - { - public: - // -- predefines file - cmFileTime PredefsTime; - // -- Mappings - MappingMapT HeaderMappings; - MappingMapT SourceMappings; - MappingMapT Includes; - // -- Discovered files - SourceFileMapT HeadersDiscovered; - // -- Output directories - std::unordered_set<std::string> OutputDirs; - // -- Mocs compilation - bool CompUpdated = false; - std::vector<std::string> CompFiles; - }; - - /** Uic settings. */ - class UicSettingsT - { - public: - struct UiFile - { - std::vector<std::string> Options; - }; - - public: - UicSettingsT(); - ~UicSettingsT(); - - UicSettingsT(UicSettingsT const&) = delete; - UicSettingsT& operator=(UicSettingsT const&) = delete; - - // -- Const methods - bool skipped(std::string const& fileName) const; - - // -- Attributes - bool Enabled = false; - bool SettingsChanged = false; - cmFileTime ExecutableTime; - std::string Executable; - std::unordered_set<std::string> SkipList; - std::vector<std::string> Options; - std::unordered_map<std::string, UiFile> UiFiles; - std::vector<std::string> SearchPaths; - cmsys::RegularExpression RegExpInclude; - }; - - /** Uic shared variables. */ - class UicEvalT - { - public: - // -- Discovered files - SourceFileMapT UiFiles; - // -- Mappings - MappingMapT Includes; - // -- Output directories - std::unordered_set<std::string> OutputDirs; - }; - - /** Abstract job class for concurrent job processing. */ - class JobT : public cmWorkerPool::JobT - { - protected: - /** Protected default constructor. */ - JobT(bool fence = false) - : cmWorkerPool::JobT(fence) - { - } - - //! Get the generator. Only valid during Process() call! - cmQtAutoMocUic* Gen() const - { - return static_cast<cmQtAutoMocUic*>(UserData()); - }; - - // -- Accessors. Only valid during Process() call! - Logger const& Log() const { return Gen()->Log(); } - BaseSettingsT const& BaseConst() const { return Gen()->BaseConst(); } - BaseEvalT& BaseEval() const { return Gen()->BaseEval(); } - MocSettingsT const& MocConst() const { return Gen()->MocConst(); } - MocEvalT& MocEval() const { return Gen()->MocEval(); } - UicSettingsT const& UicConst() const { return Gen()->UicConst(); } - UicEvalT& UicEval() const { return Gen()->UicEval(); } - - // -- Logging - std::string MessagePath(cm::string_view path) const - { - return Gen()->MessagePath(path); - } - // - Error logging with automatic abort - void LogError(GenT genType, cm::string_view message) const; - void LogCommandError(GenT genType, cm::string_view message, - std::vector<std::string> const& command, - std::string const& output) const; - - /** @brief Run an external process. Use only during Process() call! */ - bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, - std::vector<std::string> const& command, - std::string* infoMessage = nullptr); - }; - - /** Fence job utility class. */ - class JobFenceT : public JobT - { - public: - JobFenceT() - : JobT(true) - { - } - void Process() override{}; - }; - - /** Generate moc_predefs.h. */ - class JobMocPredefsT : public JobFenceT - { - void Process() override; - bool Update(std::string* reason) const; - }; - - /** File parse job base class. */ - class JobParseT : public JobT - { - public: - JobParseT(SourceFileHandleT fileHandle) - : FileHandle(std::move(fileHandle)) - { - } - - protected: - bool ReadFile(); - void CreateKeys(std::vector<IncludeKeyT>& container, - std::set<std::string> const& source, - std::size_t basePrefixLength); - void MocMacro(); - void MocDependecies(); - void MocIncludes(); - void UicIncludes(); - - protected: - SourceFileHandleT FileHandle; - std::string Content; - }; - - /** Header file parse job. */ - class JobParseHeaderT : public JobParseT - { - public: - using JobParseT::JobParseT; - void Process() override; - }; - - /** Source file parse job. */ - class JobParseSourceT : public JobParseT - { - public: - using JobParseT::JobParseT; - void Process() override; - }; - - /** Evaluate cached file parse data - moc. */ - class JobEvalCacheT : public JobT - { - protected: - std::string MessageSearchLocations() const; - std::vector<std::string> SearchLocations; - }; - - /** Evaluate cached file parse data - moc. */ - class JobEvalCacheMocT : public JobEvalCacheT - { - void Process() override; - bool EvalHeader(SourceFileHandleT source); - bool EvalSource(SourceFileHandleT const& source); - bool FindIncludedHeader(SourceFileHandleT& headerHandle, - cm::string_view includerDir, - cm::string_view includeBase); - bool RegisterIncluded(std::string const& includeString, - SourceFileHandleT includerFileHandle, - SourceFileHandleT sourceFileHandle) const; - void RegisterMapping(MappingHandleT mappingHandle) const; - std::string MessageHeader(cm::string_view headerBase) const; - }; - - /** Evaluate cached file parse data - uic. */ - class JobEvalCacheUicT : public JobEvalCacheT - { - void Process() override; - bool EvalFile(SourceFileHandleT const& sourceFileHandle); - bool FindIncludedUi(cm::string_view sourceDirPrefix, - cm::string_view includePrefix); - bool RegisterMapping(std::string const& includeString, - SourceFileHandleT includerFileHandle); - - std::string UiName; - SourceFileHandleT UiFileHandle; - }; - - /** Evaluate cached file parse data - finish */ - class JobEvalCacheFinishT : public JobFenceT - { - void Process() override; - }; - - /** Dependency probing base job. */ - class JobProbeDepsT : public JobT - { - }; - - /** Probes file dependencies and generates moc compile jobs. */ - class JobProbeDepsMocT : public JobProbeDepsT - { - void Process() override; - bool Generate(MappingHandleT const& mapping, bool compFile) const; - bool Probe(MappingT const& mapping, std::string* reason) const; - std::pair<std::string, cmFileTime> FindDependency( - std::string const& sourceDir, std::string const& includeString) const; - }; - - /** Probes file dependencies and generates uic compile jobs. */ - class JobProbeDepsUicT : public JobProbeDepsT - { - void Process() override; - bool Probe(MappingT const& mapping, std::string* reason) const; - }; - - /** Dependency probing finish job. */ - class JobProbeDepsFinishT : public JobFenceT - { - void Process() override; - }; - - /** Meta compiler base job. */ - class JobCompileT : public JobT - { - public: - JobCompileT(MappingHandleT uicMapping, std::unique_ptr<std::string> reason) - : Mapping(std::move(uicMapping)) - , Reason(std::move(reason)) - { - } - - protected: - MappingHandleT Mapping; - std::unique_ptr<std::string> Reason; - }; - - /** moc compiles a file. */ - class JobCompileMocT : public JobCompileT - { - public: - using JobCompileT::JobCompileT; - void Process() override; - }; - - /** uic compiles a file. */ - class JobCompileUicT : public JobCompileT - { - public: - using JobCompileT::JobCompileT; - void Process() override; - }; - - /** Generate mocs_compilation.cpp. */ - class JobMocsCompilationT : public JobFenceT - { - private: - void Process() override; - }; - - /** @brief The last job. */ - class JobFinishT : public JobFenceT - { - private: - void Process() override; - }; - - // -- Const settings interface - BaseSettingsT const& BaseConst() const { return this->BaseConst_; } - BaseEvalT& BaseEval() { return this->BaseEval_; } - MocSettingsT const& MocConst() const { return this->MocConst_; } - MocEvalT& MocEval() { return this->MocEval_; } - UicSettingsT const& UicConst() const { return this->UicConst_; } - UicEvalT& UicEval() { return this->UicEval_; } - - // -- Parallel job processing interface - cmWorkerPool& WorkerPool() { return WorkerPool_; } - void AbortError() { Abort(true); } - void AbortSuccess() { Abort(false); } - - // -- Utility - std::string AbsoluteBuildPath(cm::string_view relativePath) const; - std::string AbsoluteIncludePath(cm::string_view relativePath) const; - template <class JOBTYPE> - void CreateParseJobs(SourceFileMapT const& sourceMap); - std::string CollapseFullPathTS(std::string const& path) const; - -private: - // -- Abstract processing interface - bool InitFromInfo() override; - void InitJobs(); - bool Process() override; - // -- Settings file - void SettingsFileRead(); - bool SettingsFileWrite(); - // -- Parse cache - void ParseCacheRead(); - bool ParseCacheWrite(); - // -- Thread processing - void Abort(bool error); - // -- Generation - bool CreateDirectories(); - -private: - // -- Settings - BaseSettingsT BaseConst_; - BaseEvalT BaseEval_; - MocSettingsT MocConst_; - MocEvalT MocEval_; - UicSettingsT UicConst_; - UicEvalT UicEval_; - // -- Settings file - std::string SettingsFile_; - std::string SettingsStringMoc_; - std::string SettingsStringUic_; - // -- Worker thread pool - std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false); - cmWorkerPool WorkerPool_; - // -- Concurrent processing - mutable std::mutex CMakeLibMutex_; -}; +bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config); #endif diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index b0b15d4..4a3ecfa 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -5,37 +5,105 @@ #include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmDuration.h" +#include "cmFileLock.h" #include "cmFileLockResult.h" +#include "cmFileTime.h" #include "cmProcessOutput.h" #include "cmQtAutoGen.h" +#include "cmQtAutoGenerator.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" -#include <cm/string_view> - #include <algorithm> +#include <string> +#include <vector> + +namespace { -cmQtAutoRcc::cmQtAutoRcc() +/** \class cmQtAutoRccT + * \brief AUTORCC generator + */ +class cmQtAutoRccT : public cmQtAutoGenerator +{ +public: + cmQtAutoRccT(); + ~cmQtAutoRccT() override; + + cmQtAutoRccT(cmQtAutoRccT const&) = delete; + cmQtAutoRccT& operator=(cmQtAutoRccT const&) = delete; + +private: + // -- Utility + bool IsMultiConfig() const { return MultiConfig_; } + std::string MultiConfigOutput() const; + + // -- Abstract processing interface + bool InitFromInfo(InfoT const& info) override; + bool Process() override; + // -- Settings file + bool SettingsFileRead(); + bool SettingsFileWrite(); + // -- Tests + bool TestQrcRccFiles(bool& generate); + bool TestResources(bool& generate); + bool TestInfoFile(); + // -- Generation + bool GenerateRcc(); + bool GenerateWrapper(); + +private: + // -- Config settings + bool MultiConfig_ = false; + // -- Directories + std::string AutogenBuildDir_; + std::string IncludeDir_; + // -- Qt environment + std::string RccExecutable_; + cmFileTime RccExecutableTime_; + std::vector<std::string> RccListOptions_; + // -- Job + std::string LockFile_; + cmFileLock LockFileLock_; + std::string QrcFile_; + std::string QrcFileName_; + std::string QrcFileDir_; + cmFileTime QrcFileTime_; + std::string RccPathChecksum_; + std::string RccFileName_; + std::string RccFileOutput_; + std::string RccFilePublic_; + cmFileTime RccFileTime_; + std::string Reason; + std::vector<std::string> Options_; + std::vector<std::string> Inputs_; + // -- Settings file + std::string SettingsFile_; + std::string SettingsString_; + bool SettingsChanged_ = false; + bool BuildFileChanged_ = false; +}; + +cmQtAutoRccT::cmQtAutoRccT() : cmQtAutoGenerator(GenT::RCC) { } -cmQtAutoRcc::~cmQtAutoRcc() = default; +cmQtAutoRccT::~cmQtAutoRccT() = default; -bool cmQtAutoRcc::InitFromInfo() +bool cmQtAutoRccT::InitFromInfo(InfoT const& info) { // -- Required settings - if (!InfoBool("MULTI_CONFIG", MultiConfig_, true) || - !InfoString("BUILD_DIR", AutogenBuildDir_, true) || - !InfoStringConfig("INCLUDE_DIR", IncludeDir_, true) || - !InfoString("RCC_EXECUTABLE", RccExecutable_, true) || - !InfoArray("RCC_LIST_OPTIONS", RccListOptions_, false) || - !InfoString("LOCK_FILE", LockFile_, true) || - !InfoStringConfig("SETTINGS_FILE", SettingsFile_, true) || - !InfoString("SOURCE", QrcFile_, true) || - !InfoString("OUTPUT_CHECKSUM", RccPathChecksum_, true) || - !InfoString("OUTPUT_NAME", RccFileName_, true) || - !InfoArray("OPTIONS", Options_, false) || - !InfoArray("INPUTS", Inputs_, false)) { + if (!info.GetBool("MULTI_CONFIG", MultiConfig_, true) || + !info.GetString("BUILD_DIR", AutogenBuildDir_, true) || + !info.GetStringConfig("INCLUDE_DIR", IncludeDir_, true) || + !info.GetString("RCC_EXECUTABLE", RccExecutable_, true) || + !info.GetArray("RCC_LIST_OPTIONS", RccListOptions_, false) || + !info.GetString("LOCK_FILE", LockFile_, true) || + !info.GetStringConfig("SETTINGS_FILE", SettingsFile_, true) || + !info.GetString("SOURCE", QrcFile_, true) || + !info.GetString("OUTPUT_CHECKSUM", RccPathChecksum_, true) || + !info.GetString("OUTPUT_NAME", RccFileName_, true) || + !info.GetArray("OPTIONS", Options_, false) || + !info.GetArray("INPUTS", Inputs_, false)) { return false; } @@ -54,14 +122,14 @@ bool cmQtAutoRcc::InitFromInfo() // -- Checks if (!RccExecutableTime_.Load(RccExecutable_)) { - return LogInfoError(cmStrCat( + return info.LogError(cmStrCat( "The rcc executable ", MessagePath(RccExecutable_), " does not exist.")); } return true; } -bool cmQtAutoRcc::Process() +bool cmQtAutoRccT::Process() { if (!SettingsFileRead()) { return false; @@ -94,13 +162,13 @@ bool cmQtAutoRcc::Process() return SettingsFileWrite(); } -std::string cmQtAutoRcc::MultiConfigOutput() const +std::string cmQtAutoRccT::MultiConfigOutput() const { return cmStrCat(RccPathChecksum_, '/', AppendFilenameSuffix(RccFileName_, "_CMAKE_")); } -bool cmQtAutoRcc::SettingsFileRead() +bool cmQtAutoRccT::SettingsFileRead() { // Compose current settings strings { @@ -178,7 +246,7 @@ bool cmQtAutoRcc::SettingsFileRead() return true; } -bool cmQtAutoRcc::SettingsFileWrite() +bool cmQtAutoRccT::SettingsFileWrite() { // Only write if any setting changed if (SettingsChanged_) { @@ -205,7 +273,7 @@ bool cmQtAutoRcc::SettingsFileWrite() } /// Do basic checks if rcc generation is required -bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) +bool cmQtAutoRccT::TestQrcRccFiles(bool& generate) { // Test if the rcc input file exists if (!QrcFileTime_.Load(QrcFile_)) { @@ -262,7 +330,7 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) return true; } -bool cmQtAutoRcc::TestResources(bool& generate) +bool cmQtAutoRccT::TestResources(bool& generate) { // Read resource files list if (Inputs_.empty()) { @@ -301,7 +369,7 @@ bool cmQtAutoRcc::TestResources(bool& generate) return true; } -bool cmQtAutoRcc::TestInfoFile() +bool cmQtAutoRccT::TestInfoFile() { // Test if the rcc output file is older than the info file if (RccFileTime_.Older(InfoFileTime())) { @@ -324,7 +392,7 @@ bool cmQtAutoRcc::TestInfoFile() return true; } -bool cmQtAutoRcc::GenerateRcc() +bool cmQtAutoRccT::GenerateRcc() { // Make parent directory if (!MakeParentDirectory(RccFileOutput_)) { @@ -376,7 +444,7 @@ bool cmQtAutoRcc::GenerateRcc() return true; } -bool cmQtAutoRcc::GenerateWrapper() +bool cmQtAutoRccT::GenerateWrapper() { // Generate a wrapper source file on demand if (IsMultiConfig()) { @@ -426,3 +494,10 @@ bool cmQtAutoRcc::GenerateWrapper() } return true; } + +} // End of unnamed namespace + +bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config) +{ + return cmQtAutoRccT().Run(infoFile, config); +} diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h index 945b68f..a74b33a 100644 --- a/Source/cmQtAutoRcc.h +++ b/Source/cmQtAutoRcc.h @@ -5,74 +5,12 @@ #include "cmConfigure.h" // IWYU pragma: keep -#include "cmFileLock.h" -#include "cmFileTime.h" -#include "cmQtAutoGenerator.h" +#include <cm/string_view> -#include <string> -#include <vector> - -/** \class cmQtAutoRcc - * \brief AUTORCC generator +/** + * Process AUTORCC + * @return true on success */ -class cmQtAutoRcc : public cmQtAutoGenerator -{ -public: - cmQtAutoRcc(); - ~cmQtAutoRcc() override; - - cmQtAutoRcc(cmQtAutoRcc const&) = delete; - cmQtAutoRcc& operator=(cmQtAutoRcc const&) = delete; - -private: - // -- Utility - bool IsMultiConfig() const { return MultiConfig_; } - std::string MultiConfigOutput() const; - - // -- Abstract processing interface - bool InitFromInfo() override; - bool Process() override; - // -- Settings file - bool SettingsFileRead(); - bool SettingsFileWrite(); - // -- Tests - bool TestQrcRccFiles(bool& generate); - bool TestResources(bool& generate); - bool TestInfoFile(); - // -- Generation - bool GenerateRcc(); - bool GenerateWrapper(); - -private: - // -- Config settings - bool MultiConfig_ = false; - // -- Directories - std::string AutogenBuildDir_; - std::string IncludeDir_; - // -- Qt environment - std::string RccExecutable_; - cmFileTime RccExecutableTime_; - std::vector<std::string> RccListOptions_; - // -- Job - std::string LockFile_; - cmFileLock LockFileLock_; - std::string QrcFile_; - std::string QrcFileName_; - std::string QrcFileDir_; - cmFileTime QrcFileTime_; - std::string RccPathChecksum_; - std::string RccFileName_; - std::string RccFileOutput_; - std::string RccFilePublic_; - cmFileTime RccFileTime_; - std::string Reason; - std::vector<std::string> Options_; - std::vector<std::string> Inputs_; - // -- Settings file - std::string SettingsFile_; - std::string SettingsString_; - bool SettingsChanged_ = false; - bool BuildFileChanged_ = false; -}; +bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config); #endif diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index ae77d9e..62ead60 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -332,6 +332,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("C_STANDARD"); initProp("C_STANDARD_REQUIRED"); initProp("C_EXTENSIONS"); + initProp("OBJC_STANDARD"); + initProp("OBJC_STANDARD_REQUIRED"); + initProp("OBJC_EXTENSIONS"); initProp("CXX_CLANG_TIDY"); initProp("CXX_COMPILER_LAUNCHER"); initProp("CXX_CPPLINT"); @@ -340,6 +343,9 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("CXX_STANDARD"); initProp("CXX_STANDARD_REQUIRED"); initProp("CXX_EXTENSIONS"); + initProp("OBJCXX_STANDARD"); + initProp("OBJCXX_STANDARD_REQUIRED"); + initProp("OBJCXX_EXTENSIONS"); initProp("CUDA_STANDARD"); initProp("CUDA_STANDARD_REQUIRED"); initProp("CUDA_EXTENSIONS"); @@ -452,6 +458,8 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->GetType() != cmStateEnums::UTILITY) { initProp("C_VISIBILITY_PRESET"); initProp("CXX_VISIBILITY_PRESET"); + initProp("OBJC_VISIBILITY_PRESET"); + initProp("OBJCXX_VISIBILITY_PRESET"); initProp("CUDA_VISIBILITY_PRESET"); initProp("VISIBILITY_INLINES_HIDDEN"); } diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index bf856d7..7bb3dce 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -27,6 +27,7 @@ #if !defined(CMAKE_BOOTSTRAP) && defined(_WIN32) # include "bindexplib.h" +# include "cmFileTime.h" # include "cmsys/ConsoleBuf.hxx" #endif @@ -48,6 +49,8 @@ #include <sstream> #include <utility> +#include <cm/string_view> + class cmConnection; int cmcmd_cmake_ninja_depends(std::vector<std::string>::const_iterator argBeg, @@ -1057,19 +1060,15 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args) #ifndef CMAKE_BOOTSTRAP if ((args[1] == "cmake_autogen") && (args.size() >= 4)) { - cmQtAutoMocUic autoGen; - std::string const& infoFile = args[2]; - std::string const& config = args[3]; - return autoGen.Run(infoFile, config) ? 0 : 1; + cm::string_view const infoFile = args[2]; + cm::string_view const config = args[3]; + return cmQtAutoMocUic(infoFile, config) ? 0 : 1; } if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) { - cmQtAutoRcc autoRcc; - std::string const& infoFile = args[2]; - std::string config; - if (args.size() > 3) { - config = args[3]; - } - return autoRcc.Run(infoFile, config) ? 0 : 1; + cm::string_view const infoFile = args[2]; + cm::string_view const config = + (args.size() > 3) ? cm::string_view(args[3]) : cm::string_view(); + return cmQtAutoRcc(infoFile, config) ? 0 : 1; } #endif diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index c284603..789fc0e 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -2328,6 +2328,79 @@ ${CMake_SOURCE_DIR}/Utilities/Release/push.bash --dir dev -- '${CMake_BUILD_NIGH list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/CFBundleTest") ADD_TEST_MACRO(ObjC++ ObjC++) + + add_test(Objective-C.simple-build-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C/simple-build-test" + "${CMake_BINARY_DIR}/Tests/Objective-C/simple-build-test" + --build-two-config + ${build_generator_args} + --build-project simple-build-test + --build-options ${build_options} + --test-command simple-build-test + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Objective-C/simple-build-test") + + add_test(Objective-C.c-file-extension-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C/c-file-extension-test" + "${CMake_BINARY_DIR}/Tests/Objective-C/c-file-extension-test" + --build-two-config + ${build_generator_args} + --build-project c-file-extension-test + --build-options ${build_options} + --test-command c-file-extension-test + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Objective-C/c-file-extension-test") + + add_test(Objective-C.objc-file-extension-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C/objc-file-extension-test" + "${CMake_BINARY_DIR}/Tests/Objective-C/objc-file-extension-test" + --build-two-config + ${build_generator_args} + --build-project objc-file-extension-test + --build-options ${build_options} + --test-command objc-file-extension-test + ) + list(APPEND TEST_BUILD_DIRS "${CMAKE_BINARY_DIR}/Tests/Objective-C/objc-file-extension-test") + + add_test(Objective-CXX.simple-build-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C++/simple-build-test" + "${CMake_BINARY_DIR}/Tests/Objective-C++/simple-build-test" + --build-two-config + ${build_generator_args} + --build-project simple-build-test + --build-options ${build_options} + --test-command simple-build-test + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Objective-C++/simple-build-test") + + add_test(Objective-CXX.cxx-file-extension-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C++/cxx-file-extension-test" + "${CMake_BINARY_DIR}/Tests/Objective-C++/cxx-file-extension-test" + --build-two-config + ${build_generator_args} + --build-project cxx-file-extension-test + --build-options ${build_options} + --test-command cxx-file-extension-test + ) + list(APPEND TEST_BUILD_DIRS "${CMake_BINARY_DIR}/Tests/Objective-C++/cxx-file-extension-test") + + add_test(Objective-CXX.objcxx-file-extension-test ${CMAKE_CTEST_COMMAND} + --build-and-test + "${CMake_SOURCE_DIR}/Tests/Objective-C++/objcxx-file-extension-test" + "${CMake_BINARY_DIR}/Tests/Objective-C++/objcxx-file-extension-test" + --build-two-config + ${build_generator_args} + --build-project objcxx-file-extension-test + --build-options ${build_options} + --test-command objcxx-file-extension-test + ) + list(APPEND TEST_BUILD_DIRS "${CMAKE_BINARY_DIR}/Tests/Objective-C++/objcxx-file-extension-test") + endif () endif () diff --git a/Tests/CMakeOnly/CMakeLists.txt b/Tests/CMakeOnly/CMakeLists.txt index 19f3f79..03babd2 100644 --- a/Tests/CMakeOnly/CMakeLists.txt +++ b/Tests/CMakeOnly/CMakeLists.txt @@ -30,6 +30,17 @@ add_CMakeOnly_test(CheckStructHasMember) add_CMakeOnly_test(CompilerIdC) add_CMakeOnly_test(CompilerIdCXX) + +if(CMAKE_OBJC_COMPILER) + add_CMakeOnly_test(CompilerIdOBJC) + add_CMakeOnly_test(CheckOBJCCompilerFlag) +endif() + +if(CMAKE_OBJCXX_COMPILER) + add_CMakeOnly_test(CompilerIdOBJCXX) + add_CMakeOnly_test(CheckOBJCXXCompilerFlag) +endif() + if(CMAKE_Fortran_COMPILER) add_CMakeOnly_test(CompilerIdFortran) endif() diff --git a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt index ca4becb..90aa921 100644 --- a/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt +++ b/Tests/CMakeOnly/CheckLanguage/CMakeLists.txt @@ -5,10 +5,20 @@ include(CheckLanguage) set(langs ) set(expect_C 1) set(expect_CXX 1) + +if(APPLE) + set(expect_OBJC 1) + set(expect_OBJCXX 1) +endif() unset(expect_Fortran) set(expect_NoSuchLanguage 0) -foreach(lang C CXX Fortran CUDA NoSuchLanguage) +set(LANGUAGES C CXX Fortran CUDA NoSuchLanguage) +if(APPLE) + list(APPEND LANGUAGES OBJC OBJCXX) +endif() + +foreach(lang ${LANGUAGES}) check_language(${lang}) if(NOT DEFINED CMAKE_${lang}_COMPILER) message(FATAL_ERROR "check_language(${lang}) did not set result") diff --git a/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt new file mode 100644 index 0000000..a9a96ee --- /dev/null +++ b/Tests/CMakeOnly/CheckOBJCCompilerFlag/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(CheckOBJCCompilerFlag) + +include(CheckOBJCCompilerFlag) + +if(CMAKE_COMPILER_IS_GNUOBJC) + set(COMPILER_FLAG -fobjc-direct-dispatch) +else() + set(COMPILER_FLAG -fobjc-gc) +endif() + +CHECK_OBJC_COMPILER_FLAGS(${COMPILER_FLAG} HAS_COMPILER_FLAG) + +if(NOT HAS_COMPILER_FLAG) + message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}") +endif diff --git a/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt new file mode 100644 index 0000000..f83b738 --- /dev/null +++ b/Tests/CMakeOnly/CheckOBJCXXCompilerFlag/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 2.8.12) + +project(CheckOBJCXXCompilerFlag) + +include(CheckOBJCXXCompilerFlag) + +if(CMAKE_COMPILER_IS_GNUOBJCXX) + set(COMPILER_FLAG -fobjc-direct-dispatch) +else() + set(COMPILER_FLAG -fobjc-gc) +endif() + +CHECK_OBJCXX_COMPILER_FLAGS(${COMPILER_FLAG} HAS_COMPILER_FLAG) + +if(NOT HAS_COMPILER_FLAG) + message(SEND_ERROR "Test fail: HAS_COMPILER_FLAG: ${COMPILER_FLAG}") +endif() diff --git a/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt new file mode 100644 index 0000000..8f13787 --- /dev/null +++ b/Tests/CMakeOnly/CompilerIdOBJC/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.12) +project(CompilerIdOBJC OBJC) + +foreach(v + CMAKE_OBJC_COMPILER + CMAKE_OBJC_COMPILER_ID + CMAKE_OBJC_COMPILER_VERSION + ) + if(${v}) + message(STATUS "${v}=[${${v}}]") + else() + message(SEND_ERROR "${v} not set!") + endif() +endforeach() diff --git a/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt b/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt new file mode 100644 index 0000000..8f41db0 --- /dev/null +++ b/Tests/CMakeOnly/CompilerIdOBJCXX/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.8.12) +project(CompilerIdOBJCXX OBJCXX) + +foreach(v + CMAKE_OBJCXX_COMPILER + CMAKE_OBJCXX_COMPILER_ID + CMAKE_OBJCXX_COMPILER_VERSION + ) + if(${v}) + message(STATUS "${v}=[${${v}}]") + else() + message(SEND_ERROR "${v} not set!") + endif() +endforeach() diff --git a/Tests/Objective-C++/cxx-file-extension-test/CMakeLists.txt b/Tests/Objective-C++/cxx-file-extension-test/CMakeLists.txt new file mode 100644 index 0000000..0b33875 --- /dev/null +++ b/Tests/Objective-C++/cxx-file-extension-test/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.15) + +project(cxx-file-extension-test CXX) + +add_executable(cxx-file-extension-test main.mm) diff --git a/Tests/Objective-C++/cxx-file-extension-test/main.mm b/Tests/Objective-C++/cxx-file-extension-test/main.mm new file mode 100644 index 0000000..1c159a9 --- /dev/null +++ b/Tests/Objective-C++/cxx-file-extension-test/main.mm @@ -0,0 +1,8 @@ +#ifndef __OBJC__ +# error "Compiler cannot compile Objective-C" +#endif + +int main() +{ + return 0; +} diff --git a/Tests/Objective-C++/objcxx-file-extension-test/CMakeLists.txt b/Tests/Objective-C++/objcxx-file-extension-test/CMakeLists.txt new file mode 100644 index 0000000..eda7bba --- /dev/null +++ b/Tests/Objective-C++/objcxx-file-extension-test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.15) + +project(objcxx-file-extension-test OBJCXX CXX) + +add_executable(objcxx-file-extension-test main.mm) +target_link_libraries(objcxx-file-extension-test "-framework Foundation") diff --git a/Tests/Objective-C++/objcxx-file-extension-test/main.mm b/Tests/Objective-C++/objcxx-file-extension-test/main.mm new file mode 100644 index 0000000..d4aa1bb --- /dev/null +++ b/Tests/Objective-C++/objcxx-file-extension-test/main.mm @@ -0,0 +1,14 @@ +#ifndef __OBJC__ +# error "Compiler is not an Objective-C compiler." +#endif + +#import <Foundation/Foundation.h> +#include <iostream> + +int main() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + std::cout << "Hello World" << std::endl; + [pool release]; + return 0; +} diff --git a/Tests/Objective-C++/simple-build-test/CMakeLists.txt b/Tests/Objective-C++/simple-build-test/CMakeLists.txt new file mode 100644 index 0000000..cf27683 --- /dev/null +++ b/Tests/Objective-C++/simple-build-test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) + +set(CMAKE_MACOSX_RPATH OFF) + +project(simple-build-test OBJCXX) + +add_library(foo SHARED foo.mm) +target_link_libraries(foo "-framework Foundation") + +add_executable(simple-build-test main.mm) +target_link_libraries(simple-build-test "-framework Foundation" foo) diff --git a/Tests/Objective-C++/simple-build-test/foo.h b/Tests/Objective-C++/simple-build-test/foo.h new file mode 100644 index 0000000..b3fb084 --- /dev/null +++ b/Tests/Objective-C++/simple-build-test/foo.h @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +@interface Foo : NSObject { + NSNumber* age; +} + +@property (nonatomic, retain) NSNumber* age; + +@end diff --git a/Tests/Objective-C++/simple-build-test/foo.mm b/Tests/Objective-C++/simple-build-test/foo.mm new file mode 100644 index 0000000..2d452a8 --- /dev/null +++ b/Tests/Objective-C++/simple-build-test/foo.mm @@ -0,0 +1,7 @@ +#import "foo.h" + +@implementation Foo + +@synthesize age; + +@end diff --git a/Tests/Objective-C++/simple-build-test/main.mm b/Tests/Objective-C++/simple-build-test/main.mm new file mode 100644 index 0000000..7c85551 --- /dev/null +++ b/Tests/Objective-C++/simple-build-test/main.mm @@ -0,0 +1,14 @@ +#import <Foundation/Foundation.h> +#import "foo.h" +#include <iostream> + +int main(int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Foo *theFoo = [[Foo alloc] init]; + theFoo.age = [NSNumber numberWithInt:argc]; + NSLog(@"%d\n",[theFoo.age intValue]); + std::cout << [theFoo.age intValue] << std::endl; + [pool release]; + return 0; +} diff --git a/Tests/Objective-C/c-file-extension-test/CMakeLists.txt b/Tests/Objective-C/c-file-extension-test/CMakeLists.txt new file mode 100644 index 0000000..e091448 --- /dev/null +++ b/Tests/Objective-C/c-file-extension-test/CMakeLists.txt @@ -0,0 +1,5 @@ +cmake_minimum_required(VERSION 3.15) + +project(c-file-extension-test C) + +add_executable(c-file-extension-test main.m) diff --git a/Tests/Objective-C/c-file-extension-test/main.m b/Tests/Objective-C/c-file-extension-test/main.m new file mode 100644 index 0000000..1c159a9 --- /dev/null +++ b/Tests/Objective-C/c-file-extension-test/main.m @@ -0,0 +1,8 @@ +#ifndef __OBJC__ +# error "Compiler cannot compile Objective-C" +#endif + +int main() +{ + return 0; +} diff --git a/Tests/Objective-C/objc-file-extension-test/CMakeLists.txt b/Tests/Objective-C/objc-file-extension-test/CMakeLists.txt new file mode 100644 index 0000000..27e88be --- /dev/null +++ b/Tests/Objective-C/objc-file-extension-test/CMakeLists.txt @@ -0,0 +1,6 @@ +cmake_minimum_required(VERSION 3.15) + +project(objc-file-extension-test OBJC CXX) + +add_executable(objc-file-extension-test main.m) +target_link_libraries(objc-file-extension-test "-framework Foundation") diff --git a/Tests/Objective-C/objc-file-extension-test/main.m b/Tests/Objective-C/objc-file-extension-test/main.m new file mode 100644 index 0000000..2ec3917 --- /dev/null +++ b/Tests/Objective-C/objc-file-extension-test/main.m @@ -0,0 +1,12 @@ +#ifndef __OBJC__ +# error "Compiler is not an Objective-C compiler." +#endif + +#import <Foundation/Foundation.h> + +int main() +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [pool release]; + return 0; +} diff --git a/Tests/Objective-C/simple-build-test/CMakeLists.txt b/Tests/Objective-C/simple-build-test/CMakeLists.txt new file mode 100644 index 0000000..5ab46ac --- /dev/null +++ b/Tests/Objective-C/simple-build-test/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.15) + +set(CMAKE_MACOSX_RPATH OFF) + +project(simple-build-test OBJC) + +add_library(foo SHARED foo.m) +target_link_libraries(foo "-framework Foundation") + +add_executable(simple-build-test main.m) +target_link_libraries(simple-build-test "-framework Foundation" foo) diff --git a/Tests/Objective-C/simple-build-test/foo.h b/Tests/Objective-C/simple-build-test/foo.h new file mode 100644 index 0000000..b3fb084 --- /dev/null +++ b/Tests/Objective-C/simple-build-test/foo.h @@ -0,0 +1,9 @@ +#import <Foundation/Foundation.h> + +@interface Foo : NSObject { + NSNumber* age; +} + +@property (nonatomic, retain) NSNumber* age; + +@end diff --git a/Tests/Objective-C/simple-build-test/foo.m b/Tests/Objective-C/simple-build-test/foo.m new file mode 100644 index 0000000..2d452a8 --- /dev/null +++ b/Tests/Objective-C/simple-build-test/foo.m @@ -0,0 +1,7 @@ +#import "foo.h" + +@implementation Foo + +@synthesize age; + +@end diff --git a/Tests/Objective-C/simple-build-test/main.m b/Tests/Objective-C/simple-build-test/main.m new file mode 100644 index 0000000..970d554 --- /dev/null +++ b/Tests/Objective-C/simple-build-test/main.m @@ -0,0 +1,12 @@ +#import <Foundation/Foundation.h> +#import "foo.h" + +int main(int argc, char **argv) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + Foo *theFoo = [[Foo alloc] init]; + theFoo.age = [NSNumber numberWithInt:argc]; + NSLog(@"%d\n",[theFoo.age intValue]); + [pool release]; + return 0; +} diff --git a/Tests/RunCMake/FPHSA/CustomMessageConfig.cmake b/Tests/RunCMake/FPHSA/CustomMessageConfig.cmake new file mode 100644 index 0000000..e25db1a --- /dev/null +++ b/Tests/RunCMake/FPHSA/CustomMessageConfig.cmake @@ -0,0 +1 @@ +# pseudo config module diff --git a/Tests/RunCMake/FPHSA/CustomMessageConfigVersion.cmake b/Tests/RunCMake/FPHSA/CustomMessageConfigVersion.cmake new file mode 100644 index 0000000..b7c9e18 --- /dev/null +++ b/Tests/RunCMake/FPHSA/CustomMessageConfigVersion.cmake @@ -0,0 +1,4 @@ +# pseudo find_module + +set (PACKAGE_VERSION 2) +set (PACKAGE_VERSION_UNSUITABLE TRUE) diff --git a/Tests/RunCMake/FPHSA/FindCustomMessage.cmake b/Tests/RunCMake/FPHSA/FindCustomMessage.cmake new file mode 100644 index 0000000..4d67db8 --- /dev/null +++ b/Tests/RunCMake/FPHSA/FindCustomMessage.cmake @@ -0,0 +1,17 @@ +# pseudo find_module + +if (REASON_FAILURE_MESSAGE) + list (PREPEND REASON_FAILURE_MESSAGE "REASON_FAILURE_MESSAGE") +endif() + +include(FindPackageHandleStandardArgs) + +if (CONFIG_MODE) + find_package (CustomMessage QUIET CONFIG HINTS "${CMAKE_MODULE_PATH}") + find_package_handle_standard_args(CustomMessage CONFIG_MODE + ${REASON_FAILURE_MESSAGE}) +else() + find_package_handle_standard_args(CustomMessage REQUIRED_VARS FOOBAR + VERSION_VAR CustomMessage_VERSION + ${REASON_FAILURE_MESSAGE}) +endif() diff --git a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake index dd73cd4..f3e6c3e 100644 --- a/Tests/RunCMake/FPHSA/RunCMakeTest.cmake +++ b/Tests/RunCMake/FPHSA/RunCMakeTest.cmake @@ -39,3 +39,10 @@ unset(RunCMake_DEFAULT_stderr) # check if searching for a version 0 works list(APPEND RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DPseudo_VERSION=0") run_cmake(exact_0_matching) + +# check custom error message +set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DCustomMessage_VERSION=1.2.3.4") +run_cmake(custom_message_1) +set(RunCMake_TEST_OPTIONS "-DCMAKE_MODULE_PATH=${CMAKE_CURRENT_LIST_DIR}" "-DCONFIG_MODE=TRUE") +run_cmake(custom_message_2) +run_cmake(custom_message_3) diff --git a/Tests/RunCMake/FPHSA/custom_message_1-result.txt b/Tests/RunCMake/FPHSA/custom_message_1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FPHSA/custom_message_1-stderr.txt b/Tests/RunCMake/FPHSA/custom_message_1-stderr.txt new file mode 100644 index 0000000..992fe39 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_1-stderr.txt @@ -0,0 +1,7 @@ +^CMake Error at .+/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): + Could NOT find CustomMessage \(missing: FOOBAR\) \(found suitable version + "1\.2\.3\.4", minimum required is "1\.2"\) + + Reason given by package: Reason Failure + +Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/FPHSA/custom_message_1.cmake b/Tests/RunCMake/FPHSA/custom_message_1.cmake new file mode 100644 index 0000000..330de50 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_1.cmake @@ -0,0 +1,4 @@ + +set (REASON_FAILURE_MESSAGE "Reason Failure") + +find_package(CustomMessage 1.2 REQUIRED) diff --git a/Tests/RunCMake/FPHSA/custom_message_2-result.txt b/Tests/RunCMake/FPHSA/custom_message_2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FPHSA/custom_message_2-stderr.txt b/Tests/RunCMake/FPHSA/custom_message_2-stderr.txt new file mode 100644 index 0000000..4940752 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_2-stderr.txt @@ -0,0 +1,8 @@ +^CMake Error at .+/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): + Could NOT find CustomMessage \(Required is at least version "1\.2"\), checked + the following files: + + .+/Tests/RunCMake/FPHSA/CustomMessageConfig.cmake \(version 2\) + Reason given by package: Not Found Message + +Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/FPHSA/custom_message_2.cmake b/Tests/RunCMake/FPHSA/custom_message_2.cmake new file mode 100644 index 0000000..a3f2d96 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_2.cmake @@ -0,0 +1,5 @@ + +unset (REASON_FAILURE_MESSAGE) +set (CustomMessage_NOT_FOUND_MESSAGE "Not Found Message") + +find_package(CustomMessage 1.2 REQUIRED) diff --git a/Tests/RunCMake/FPHSA/custom_message_3-result.txt b/Tests/RunCMake/FPHSA/custom_message_3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/FPHSA/custom_message_3-stderr.txt b/Tests/RunCMake/FPHSA/custom_message_3-stderr.txt new file mode 100644 index 0000000..dc55843 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_3-stderr.txt @@ -0,0 +1,9 @@ +^CMake Error at .+/Modules/FindPackageHandleStandardArgs.cmake:[0-9]+ \(message\): + Could NOT find CustomMessage \(Required is at least version "1\.2"\), checked + the following files: + + .+/Tests/RunCMake/FPHSA/CustomMessageConfig.cmake \(version 2\) + Reason given by package: Not Found Message + Reason Failure + +Call Stack \(most recent call first\): diff --git a/Tests/RunCMake/FPHSA/custom_message_3.cmake b/Tests/RunCMake/FPHSA/custom_message_3.cmake new file mode 100644 index 0000000..203e012 --- /dev/null +++ b/Tests/RunCMake/FPHSA/custom_message_3.cmake @@ -0,0 +1,5 @@ + +set (REASON_FAILURE_MESSAGE "Reason Failure") +set (CustomMessage_NOT_FOUND_MESSAGE "Not Found Message") + +find_package(CustomMessage 1.2 REQUIRED) diff --git a/Tests/TryCompile/CMakeLists.txt b/Tests/TryCompile/CMakeLists.txt index 54e96a2..498e556 100644 --- a/Tests/TryCompile/CMakeLists.txt +++ b/Tests/TryCompile/CMakeLists.txt @@ -313,6 +313,60 @@ if(CMAKE_C_COMPILER_ID STREQUAL "GNU") TEST_ASSERT(C_STRICT_PROTOTYPES "CHECK_C_COMPILER_FLAG failed -Werror -Wstrict-prototypes") endif() +######################################################################### +# +# Test that the CHECK_OBJCC_SOURCE_COMPILES, CHECK_OBJCXX_SOURCE_COMPILES +# CHECK_OBJC_SOURCE_RUNS and CHECK_OBJCXX_SOURCE_RUNS macros work + +if (APPLE) + enable_language(OBJC) + enable_language(OBJCXX) + + include(CheckOBJCSourceCompiles) + include(CheckOBJCXXSourceCompiles) + include(CheckOBJCSourceRuns) + include(CheckOBJCXXSourceRuns) + + CHECK_OBJC_SOURCE_COMPILES("I don't build in Objective-C" OBJC_BUILD_SHOULD_FAIL) + CHECK_OBJC_SOURCE_COMPILES("int main() { return 0; }" SIMPLE_OBJC_BUILD_SHOULD_WORK) + + TEST_FAIL(OBJC_BUILD_SHOULD_FAIL "CHECK_OBJC_SOURCE_COMPILES() succeeded, but should have failed") + TEST_ASSERT(SIMPLE_OBJC_BUILD_SHOULD_WORK "CHECK_OBJC_SOURCE_COMPILES() failed, but should have succeeded") + + set(CMAKE_REQUIRED_LIBRARIES "-framework Foundation") + + CHECK_OBJC_SOURCE_COMPILES("#import <Foundation/Foundation.h>\nint main()\n{\nNSObject *foo;\nreturn 0;\n}\n" OBJC_BUILD_SHOULD_WORK) + CHECK_OBJC_SOURCE_RUNS("int main() { return 2; }" SIMPLE_OBJC_RUN_SHOULD_FAIL) + CHECK_OBJC_SOURCE_RUNS("int main() { return 0; }" SIMPLE_OBJC_RUN_SHOULD_WORK) + CHECK_OBJC_SOURCE_RUNS("#import <Foundation/Foundation.h>\nint main()\n{\nNSObject *foo;\nreturn 2;\n}\n" OBJC_RUN_SHOULD_FAIL) + CHECK_OBJC_SOURCE_RUNS("#import <Foundation/Foundation.h>\nint main()\n{\nNSObject *foo;\nreturn 0;\n}\n" OBJC_RUN_SHOULD_WORK) + + TEST_ASSERT(OBJC_BUILD_SHOULD_WORK "CHECK_OBJC_SOURCE_COMPILES() failed, but should have succeeded") + TEST_FAIL(SIMPLE_OBJC_RUN_SHOULD_FAIL "CHECK_OBJC_SOURC_RUNS() succeeds, but should have failed") + TEST_ASSERT(SIMPLE_OBJC_RUN_SHOULD_WORK "CHECK_OBJC_SOURCE_RUNS() failed, but should have succeeded") + TEST_FAIL(OBJC_RUN_SHOULD_FAIL "CHECK_OBJC_SOURCE_RUNS() succeeds, but should have failed") + TEST_ASSERT(OBJC_RUN_SHOULD_WORK "CHECK_OBJC_SOURCE_RUNS() failed, but should have succeeded") + + + CHECK_OBJCXX_SOURCE_COMPILES("I don't build in Objective-C++" OBJCXX_BUILD_SHOULD_FAIL) + CHECK_OBJCXX_SOURCE_COMPILES("int main() { return 0; }" SIMPLE_OBJCXX_BUILD_SHOULD_WORK) + + TEST_FAIL(OBJCXX_BUILD_SHOULD_FAIL "CHECK_OBJCXX_SOURCE_COMPILES() succeeded, but should have failed") + TEST_ASSERT(SIMPLE_OBJCXX_BUILD_SHOULD_WORK "CHECK_OBJCXX_SOURCE_COMPILES() failed, but should have succeeded") + + CHECK_OBJCXX_SOURCE_COMPILES("#import <Foundation/Foundation.h>\n#include <iostream>\nint main()\n{\nNSObject *foo;\nstd::cout << \"Hello\" << std::endl;\nreturn 0;\n}\n" OBJCXX_BUILD_SHOULD_WORK) + CHECK_OBJCXX_SOURCE_RUNS("int main() { return 2; }" SIMPLE_OBJCXX_RUN_SHOULD_FAIL) + CHECK_OBJCXX_SOURCE_RUNS("int main() { return 0; }" SIMPLE_OBJCXX_RUN_SHOULD_WORK) + CHECK_OBJCXX_SOURCE_RUNS("#import <Foundation/Foundation.h>\n#include <vector>\nint main()\n{\nNSObject *foo;\nstd::vector<int> bar;\nreturn 2;\n}\n" OBJCXX_RUN_SHOULD_FAIL) + CHECK_OBJCXX_SOURCE_RUNS("#import <Foundation/Foundation.h>\n#include <vector>\nint main()\n{\nNSObject *foo;\nstd::vector<int> bar;\nreturn 0;\n}\n" OBJCXX_RUN_SHOULD_WORK) + + TEST_ASSERT(OBJCXX_BUILD_SHOULD_WORK "CHECK_OBJCXX_SOURCE_COMPILES() failed, but should have succeeded") + TEST_FAIL(SIMPLE_OBJCXX_RUN_SHOULD_FAIL "CHECK_OBJCXX_SOURC_RUNS() succeeds, but should have failed") + TEST_ASSERT(SIMPLE_OBJCXX_RUN_SHOULD_WORK "CHECK_OBJCXX_SOURCE_RUNS() failed, but should have succeeded") + TEST_FAIL(OBJCXX_RUN_SHOULD_FAIL "CHECK_OBJCXX_SOURCE_RUNS() succeeds, but should have failed") + TEST_ASSERT(OBJCXX_RUN_SHOULD_WORK "CHECK_OBJCXX_SOURCE_RUNS() failed, but should have succeeded") +endif() + ####################################################################### # # also test that the check_prototype_definition macro works |