diff options
288 files changed, 7644 insertions, 2095 deletions
@@ -1,2 +1,7 @@ # Exclude MacOS Finder files. .DS_Store + +*.user* + +*.pyc +Testing diff --git a/Auxiliary/vim/syntax/cmake.vim b/Auxiliary/vim/syntax/cmake.vim index 715676d..11b0fcb 100644 --- a/Auxiliary/vim/syntax/cmake.vim +++ b/Auxiliary/vim/syntax/cmake.vim @@ -44,7 +44,7 @@ syn keyword cmakeModule \ contained syn keyword cmakeKWExternalProject - \ ALGO ALWAYS BINARY_DIR BUILD_ALWAYS BUILD_BYPRODUCTS BUILD_COMMAND BUILD_IN_SOURCE BYPRODUCTS CMAKE_ARGS CMAKE_CACHE_ARGS CMAKE_CACHE_DEFAULT_ARGS COMMAND COMMENT CONFIGURE_COMMAND CVS CVSROOT CVS_ CVS_MODULE CVS_REPOSITORY CVS_TAG DEPENDEES DEPENDERS DEPENDS DIRECTORY DOWNLOAD_COMMAND DOWNLOAD_DIR DOWNLOAD_NAME DOWNLOAD_NO_PROGRESS EP_BASE EP_INDEPENDENT_STEP_TARGETS EP_PREFIX EP_STEP_TARGETS EP_UPDATE_DISCONNECTED EXCLUDE_FROM_ALL EXCLUDE_FROM_MAIN FORCE GIT_REMOTE_NAME GIT_REPOSITORY GIT_SUBMODULES GIT_TAG HG_REPOSITORY HG_TAG INDEPENDENT INDEPENDENT_STEP_TARGETS INSTALL_COMMAND INSTALL_DIR JOB_POOLS LIST_SEPARATOR LOG LOG_BUILD LOG_CONFIGURE LOG_DOWNLOAD LOG_INSTALL LOG_TEST LOG_UPDATE NO_DEPENDS PATCH_COMMAND PREFIX PROPERTY SOURCE_DIR STAMP_DIR STEP_TARGETS SVN_ SVN_PASSWORD SVN_REPOSITORY SVN_REVISION SVN_TRUST_CERT SVN_USERNAME TEST_AFTER_INSTALL TEST_BEFORE_INSTALL TEST_COMMAND TEST_EXCLUDE_FROM_MAIN TIMEOUT TLS_CAINFO TLS_VERIFY TMP_DIR UPDATE_COMMAND UPDATE_DISCONNECTED URL URL_HASH USES_TERMINAL USES_TERMINAL_BUILD USES_TERMINAL_CONFIGURE USES_TERMINAL_DOWNLOAD USES_TERMINAL_INSTALL USES_TERMINAL_TEST USES_TERMINAL_UPDATE WORKING_DIRECTORY _COMMAND _DIR + \ ALGO ALWAYS BINARY_DIR BUILD_ALWAYS BUILD_BYPRODUCTS BUILD_COMMAND BUILD_IN_SOURCE BYPRODUCTS CMAKE_ARGS CMAKE_CACHE_ARGS CMAKE_CACHE_DEFAULT_ARGS COMMAND COMMENT CONFIGURE_COMMAND CVS CVSROOT CVS_ CVS_MODULE CVS_REPOSITORY CVS_TAG DEPENDEES DEPENDERS DEPENDS DIRECTORY DOWNLOAD_COMMAND DOWNLOAD_DIR DOWNLOAD_NAME DOWNLOAD_NO_PROGRESS EP_BASE EP_INDEPENDENT_STEP_TARGETS EP_PREFIX EP_STEP_TARGETS EP_UPDATE_DISCONNECTED EXCLUDE_FROM_ALL EXCLUDE_FROM_MAIN FORCE GIT_REMOTE_NAME GIT_REPOSITORY GIT_SUBMODULES GIT_TAG HG_REPOSITORY HG_TAG INDEPENDENT INDEPENDENT_STEP_TARGETS INSTALL_COMMAND INSTALL_DIR JOB_POOLS LIST_SEPARATOR LOG LOG_BUILD LOG_CONFIGURE LOG_DOWNLOAD LOG_INSTALL LOG_TEST LOG_UPDATE NO_DEPENDS PATCH_COMMAND PREFIX PROPERTY SOURCE_DIR STAMP_DIR STEP_TARGETS SVN_ SVN_PASSWORD SVN_REPOSITORY SVN_REVISION SVN_TRUST_CERT SVN_USERNAME TEST_AFTER_INSTALL TEST_BEFORE_INSTALL TEST_COMMAND TEST_EXCLUDE_FROM_MAIN TIMEOUT TLS_CAINFO TLS_VERIFY TMP_DIR UPDATE_COMMAND UPDATE_DISCONNECTED URL URL_HASH HTTP_USERNAME HTTP_PASSWORD HTTP_HEADER USES_TERMINAL USES_TERMINAL_BUILD USES_TERMINAL_CONFIGURE USES_TERMINAL_DOWNLOAD USES_TERMINAL_INSTALL USES_TERMINAL_TEST USES_TERMINAL_UPDATE WORKING_DIRECTORY _COMMAND _DIR \ contained syn keyword cmakeKWadd_compile_options diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ef2ca2..2ec8b57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= -cmake_minimum_required(VERSION 2.8.4 FATAL_ERROR) +cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR) if(POLICY CMP0025) cmake_policy(SET CMP0025 NEW) endif() @@ -702,6 +702,18 @@ endif() # setup some Testing support (a macro defined in this file) CMAKE_SETUP_TESTING() +# Check whether to build server mode or not: +set(CMake_HAVE_SERVER_MODE 0) +if(NOT CMake_TEST_EXTERNAL_CMAKE AND NOT CMAKE_BOOTSTRAP AND CMAKE_USE_LIBUV) + list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_auto_type CMake_HAVE_CXX_AUTO_TYPE) + list(FIND CMAKE_CXX_COMPILE_FEATURES cxx_range_for CMake_HAVE_CXX_RANGE_FOR) + if(CMake_HAVE_CXX_AUTO_TYPE AND CMake_HAVE_CXX_RANGE_FOR) + if(CMake_HAVE_CXX_MAKE_UNIQUE) + set(CMake_HAVE_SERVER_MODE 1) + endif() + endif() +endif() + if(NOT CMake_TEST_EXTERNAL_CMAKE) if(NOT CMake_VERSION_IS_RELEASE) if(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND diff --git a/CompileFlags.cmake b/CompileFlags.cmake index 3c053fa..535f68b 100644 --- a/CompileFlags.cmake +++ b/CompileFlags.cmake @@ -64,7 +64,7 @@ endif() # Workaround for short jump tables on PA-RISC if(CMAKE_SYSTEM_PROCESSOR MATCHES "^parisc") - if(CMAKE_COMPILER_IS_GNUC) + if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mlong-calls") endif() if(CMAKE_COMPILER_IS_GNUCXX) diff --git a/Help/command/export.rst b/Help/command/export.rst index 4419dc1..53675a7 100644 --- a/Help/command/export.rst +++ b/Help/command/export.rst @@ -55,3 +55,18 @@ build tree. In some cases, for example for packaging and for system wide installations, it is not desirable to write the user package registry. If the :variable:`CMAKE_EXPORT_NO_PACKAGE_REGISTRY` variable is enabled, the ``export(PACKAGE)`` command will do nothing. + +:: + + export(TARGETS [target1 [target2 [...]]] [ANDROID_MK <filename>]) + +This signature exports cmake built targets to the android ndk build system +by creating an Android.mk file that references the prebuilt targets. The +Android NDK supports the use of prebuilt libraries, both static and shared. +This allows cmake to build the libraries of a project and make them available +to an ndk build system complete with transitive dependencies, include flags +and defines required to use the libraries. The signature takes a list of +targets and puts them in the Android.mk file specified by the ``<filename>`` +given. This signature can only be used if policy CMP0022 is NEW for all +targets given. A error will be issued if that policy is set to OLD for one +of the targets. diff --git a/Help/command/file.rst b/Help/command/file.rst index 256d16d..77e9f62 100644 --- a/Help/command/file.rst +++ b/Help/command/file.rst @@ -222,6 +222,12 @@ Options to both ``DOWNLOAD`` and ``UPLOAD`` are: ``TIMEOUT <seconds>`` Terminate the operation after a given total time has elapsed. +``USERPWD <username>:<password>`` + Set username and password for operation. + +``HTTPHEADER <HTTP-header>`` + HTTP header for operation. Suboption can be repeated several times. + Additional options to ``DOWNLOAD`` are: ``EXPECTED_HASH ALGO=<value>`` diff --git a/Help/command/find_package.rst b/Help/command/find_package.rst index c44fe86..2cb1e5f 100644 --- a/Help/command/find_package.rst +++ b/Help/command/find_package.rst @@ -170,11 +170,21 @@ is acceptable the following variables are set: ``<package>_VERSION_COUNT`` number of version components, 0 to 4 -and the corresponding package configuration file is loaded. When -multiple package configuration files are available whose version files +and the corresponding package configuration file is loaded. +When multiple package configuration files are available whose version files claim compatibility with the version requested it is unspecified which -one is chosen. No attempt is made to choose a highest or closest -version number. +one is chosen: unless the variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` +is set no attempt is made to choose a highest or closest version number. + +To control the order in which ``find_package`` checks for compatibiliy use +the two variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` and +:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`. +For instance in order to select the highest version one can set:: + + SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) + SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) + +before calling ``find_package``. Config mode provides an elaborate interface and search procedure. Much of the interface is provided for completeness and for use diff --git a/Help/command/include.rst b/Help/command/include.rst index c391561..eeca4c6 100644 --- a/Help/command/include.rst +++ b/Help/command/include.rst @@ -15,10 +15,10 @@ is present, then no error is raised if the file does not exist. If which has been included or NOTFOUND if it failed. If a module is specified instead of a file, the file with name -<modulename>.cmake is searched first in :variable:`CMAKE_MODULE_PATH`, +``<modulename>.cmake`` is searched first in :variable:`CMAKE_MODULE_PATH`, then in the CMake module directory. There is one exception to this: if -the file which calls ``include()`` is located itself in the CMake module -directory, then first the CMake module directory is searched and +the file which calls ``include()`` is located itself in the CMake builtin +module directory, then first the CMake builtin module directory is searched and :variable:`CMAKE_MODULE_PATH` afterwards. See also policy :policy:`CMP0017`. See the :command:`cmake_policy` command documentation for discussion of the diff --git a/Help/command/install.rst b/Help/command/install.rst index aaf12cc..d57dd75 100644 --- a/Help/command/install.rst +++ b/Help/command/install.rst @@ -314,7 +314,8 @@ Installing Exports :: install(EXPORT <export-name> DESTINATION <dir> - [NAMESPACE <namespace>] [FILE <name>.cmake] + [NAMESPACE <namespace>] [[FILE <name>.cmake]| + [EXPORT_ANDROID_MK <name>.mk]] [PERMISSIONS permissions...] [CONFIGURATIONS [Debug|Release|...]] [EXPORT_LINK_INTERFACE_LIBRARIES] @@ -342,6 +343,13 @@ specified that does not match that given to the targets associated with included in the export but a target to which it links is not included the behavior is unspecified. +In additon to cmake language files, the ``EXPORT_ANDROID_MK`` option maybe +used to specifiy an export to the android ndk build system. The Android +NDK supports the use of prebuilt libraries, both static and shared. This +allows cmake to build the libraries of a project and make them available +to an ndk build system complete with transitive dependencies, include flags +and defines required to use the libraries. + The ``EXPORT`` form is useful to help outside projects use targets built and installed by the current project. For example, the code @@ -349,9 +357,11 @@ and installed by the current project. For example, the code install(TARGETS myexe EXPORT myproj DESTINATION bin) install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj) + install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules) will install the executable myexe to ``<prefix>/bin`` and code to import -it in the file ``<prefix>/lib/myproj/myproj.cmake``. An outside project +it in the file ``<prefix>/lib/myproj/myproj.cmake`` and +``<prefix>/lib/share/ndk-modules/Android.mk``. An outside project may load this file with the include command and reference the ``myexe`` executable from the installation tree using the imported target name ``mp_myexe`` as if the target were built in its own tree. diff --git a/Help/command/separate_arguments.rst b/Help/command/separate_arguments.rst index 0e3e5a5..1fd3cd1 100644 --- a/Help/command/separate_arguments.rst +++ b/Help/command/separate_arguments.rst @@ -13,19 +13,21 @@ entire command line must be given in one "<args>" argument. The ``UNIX_COMMAND`` mode separates arguments by unquoted whitespace. It recognizes both single-quote and double-quote pairs. A backslash -escapes the next literal character (\" is "); there are no special -escapes (\n is just n). +escapes the next literal character (``\"`` is ``"``); there are no special +escapes (``\n`` is just ``n``). The ``WINDOWS_COMMAND`` mode parses a windows command-line using the same syntax the runtime library uses to construct argv at startup. It separates arguments by whitespace that is not double-quoted. Backslashes are literal unless they precede double-quotes. See the -MSDN article "Parsing C Command-Line Arguments" for details. +MSDN article `Parsing C Command-Line Arguments`_ for details. + +.. _`Parsing C Command-Line Arguments`: https://msdn.microsoft.com/library/a1y7w461.aspx :: - separate_arguments(VARIABLE) + separate_arguments(<var>) -Convert the value of ``VARIABLE`` to a semi-colon separated list. All +Convert the value of ``<var>`` to a semi-colon separated list. All spaces are replaced with ';'. This helps with generating command lines. diff --git a/Help/command/string.rst b/Help/command/string.rst index 19a095a..8028333 100644 --- a/Help/command/string.rst +++ b/Help/command/string.rst @@ -278,12 +278,14 @@ specifiers: %I The hour on a 12-hour clock (01-12). %j The day of the current year (001-366). %m The month of the current year (01-12). + %b Abbreviated month name (e.g. Oct). %M The minute of the current hour (00-59). %s Seconds since midnight (UTC) 1-Jan-1970 (UNIX time). %S The second of the current minute. 60 represents a leap second. (00-60) %U The week number of the current year (00-53). %w The day of the current week. 0 is Sunday. (0-6) + %a Abbreviated weekday name (e.g. Fri). %y The last two digits of the current year (00-99) %Y The current year. diff --git a/Help/index.rst b/Help/index.rst index 2d3f156..97cd107 100644 --- a/Help/index.rst +++ b/Help/index.rst @@ -32,6 +32,7 @@ Reference Manuals /manual/cmake-generator-expressions.7 /manual/cmake-generators.7 /manual/cmake-language.7 + /manual/cmake-server.7 /manual/cmake-modules.7 /manual/cmake-packages.7 /manual/cmake-policies.7 diff --git a/Help/manual/cmake-properties.7.rst b/Help/manual/cmake-properties.7.rst index 0f1bfad..2cb6a1a 100644 --- a/Help/manual/cmake-properties.7.rst +++ b/Help/manual/cmake-properties.7.rst @@ -54,6 +54,8 @@ Properties on Directories :maxdepth: 1 /prop_dir/ADDITIONAL_MAKE_CLEAN_FILES + /prop_dir/BINARY_DIR + /prop_dir/BUILDSYSTEM_TARGETS /prop_dir/CACHE_VARIABLES /prop_dir/CLEAN_NO_CUSTOM /prop_dir/CMAKE_CONFIGURE_DEPENDS @@ -73,6 +75,8 @@ Properties on Directories /prop_dir/RULE_LAUNCH_COMPILE /prop_dir/RULE_LAUNCH_CUSTOM /prop_dir/RULE_LAUNCH_LINK + /prop_dir/SOURCE_DIR + /prop_dir/SUBDIRECTORIES /prop_dir/TEST_INCLUDE_FILE /prop_dir/VARIABLES /prop_dir/VS_GLOBAL_SECTION_POST_section diff --git a/Help/manual/cmake-server.7.rst b/Help/manual/cmake-server.7.rst new file mode 100644 index 0000000..75aa0ee --- /dev/null +++ b/Help/manual/cmake-server.7.rst @@ -0,0 +1,237 @@ +.. cmake-manual-description: CMake Server + +cmake-server(7) +*************** + +.. only:: html + + .. contents:: + +Introduction +============ + +:manual:`cmake(1)` is capable of providing semantic information about +CMake code it executes to generate a buildsystem. If executed with +the ``-E server`` command line options, it starts in a long running mode +and allows a client to request the available information via a JSON protocol. + +The protocol is designed to be useful to IDEs, refactoring tools, and +other tools which have a need to understand the buildsystem in entirety. + +A single :manual:`cmake-buildsystem(7)` may describe buildsystem contents +and build properties which differ based on +:manual:`generation-time context <cmake-generator-expressions(7)>` +including: + +* The Platform (eg, Windows, APPLE, Linux). +* The build configuration (eg, Debug, Release, Coverage). +* The Compiler (eg, MSVC, GCC, Clang) and compiler version. +* The language of the source files compiled. +* Available compile features (eg CXX variadic templates). +* CMake policies. + +The protocol aims to provide information to tooling to satisfy several +needs: + +#. Provide a complete and easily parsed source of all information relevant + to the tooling as it relates to the source code. There should be no need + for tooling to parse generated buildsystems to access include directories + or compile definitions for example. +#. Semantic information about the CMake buildsystem itself. +#. Provide a stable interface for reading the information in the CMake cache. +#. Information for determining when cmake needs to be re-run as a result of + file changes. + + +Operation +========= + +Start :manual:`cmake(1)` in the server command mode, supplying the path to +the build directory to process:: + + cmake -E server + +The server will start up and reply with an hello message on stdout:: + + [== CMake Server ==[ + {"supportedProtocolVersions":[{"major":0,"minor":1}],"type":"hello"} + ]== CMake Server ==] + +Messages sent to and from the process are wrapped in magic strings:: + + [== CMake Server ==[ + { + ... some JSON message ... + } + ]== CMake Server ==] + +The server is now ready to accept further requests via stdin. + + +Debugging +========= + +CMake server mode can be asked to provide statistics on execution times, etc. +or to dump a copy of the response into a file. This is done passing a "debug" +JSON object as a child of the request. + +The debug object supports the "showStats" key, which takes a boolean and makes +the server mode return a "zzzDebug" object with stats as part of its response. +"dumpToFile" takes a string value and will cause the cmake server to copy +the response into the given filename. + +This is a response from the cmake server with "showStats" set to true:: + + [== CMake Server ==[ + { + "cookie":"", + "errorMessage":"Waiting for type \"handshake\".", + "inReplyTo":"unknown", + "type":"error", + "zzzDebug": { + "dumpFile":"/tmp/error.txt", + "jsonSerialization":0.011016, + "size":111, + "totalTime":0.025995 + } + } + ]== CMake Server ==] + +The server has made a copy of this response into the file /tmp/error.txt and +took 0.011 seconds to turn the JSON response into a string, and it took 0.025 +seconds to process the request in total. The reply has a size of 111 bytes. + + +Protocol API +============ + + +General Message Layout +---------------------- + +All messages need to have a "type" value, which identifies the type of +message that is passed back or forth. E.g. the initial message sent by the +server is of type "hello". Messages without a type will generate an response +of type "error". + +All requests sent to the server may contain a "cookie" value. This value +will he handed back unchanged in all responses triggered by the request. + +All responses will contain a value "inReplyTo", which may be empty in +case of parse errors, but will contain the type of the request message +in all other cases. + + +Type "reply" +^^^^^^^^^^^^ + +This type is used by the server to reply to requests. + +The message may -- depending on the type of the original request -- +contain values. + +Example:: + + [== CMake Server ==[ + {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} + ]== CMake Server ==] + + +Type "error" +^^^^^^^^^^^^ + +This type is used to return an error condition to the client. It will +contain an "errorMessage". + +Example:: + + [== CMake Server ==[ + {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} + ]== CMake Server ==] + + +Type "progress" +^^^^^^^^^^^^^^^ + +When the server is busy for a long time, it is polite to send back replies of +type "progress" to the client. These will contain a "progressMessage" with a +string describing the action currently taking place as well as +"progressMinimum", "progressMaximum" and "progressCurrent" with integer values +describing the range of progess. + +Messages of type "progress" will be followed by more "progress" messages or with +a message of type "reply" or "error" that complete the request. + +"progress" messages may not be emitted after the "reply" or "error" message for +the request that triggered the responses was delivered. + + +Type "message" +^^^^^^^^^^^^^^ + +A message is triggered when the server processes a request and produces some +form of output that should be displayed to the user. A Message has a "message" +with the actual text to display as well as a "title" with a suggested dialog +box title. + +Example:: + + [== CMake Server ==[ + {"cookie":"","message":"Something happened.","title":"Title Text","inReplyTo":"handshake","type":"message"} + ]== CMake Server ==] + + +Specific Message Types +---------------------- + + +Type "hello" +^^^^^^^^^^^^ + +The initial message send by the cmake server on startup is of type "hello". +This is the only message ever sent by the server that is not of type "reply", +"progress" or "error". + +It will contain "supportedProtocolVersions" with an array of server protocol +versions supported by the cmake server. These are JSON objects with "major" and +"minor" keys containing non-negative integer values. + +Example:: + + [== CMake Server ==[ + {"supportedProtocolVersions":[{"major":0,"minor":1}],"type":"hello"} + ]== CMake Server ==] + + +Type "handshake" +^^^^^^^^^^^^^^^^ + +The first request that the client may send to the server is of type "handshake". + +This request needs to pass one of the "supportedProtocolVersions" of the "hello" +type response received earlier back to the server in the "protocolVersion" field. + +Each protocol version may request additional attributes to be present. + +Protocol version 1.0 requires the following attributes to be set: + + * "sourceDirectory" with a path to the sources + * "buildDirectory" with a path to the build directory + * "generator" with the generator name + * "extraGenerator" (optional!) with the extra generator to be used. + +Example:: + + [== CMake Server ==[ + {"cookie":"zimtstern","type":"handshake","protocolVersion":{"major":0}, + "sourceDirectory":"/home/code/cmake", "buildDirectory":"/tmp/testbuild", + "generator":"Ninja"} + ]== CMake Server ==] + +which will result in a response type "reply":: + + [== CMake Server ==[ + {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} + ]== CMake Server ==] + +indicating that the server is ready for action. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index b14f667..9e0efe9 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -38,6 +38,8 @@ Variables that Provide Information /variable/CMAKE_EXTRA_GENERATOR /variable/CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES /variable/CMAKE_FIND_PACKAGE_NAME + /variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION + /variable/CMAKE_FIND_PACKAGE_SORT_ORDER /variable/CMAKE_GENERATOR /variable/CMAKE_GENERATOR_PLATFORM /variable/CMAKE_GENERATOR_TOOLSET @@ -332,7 +334,9 @@ Variables for Languages .. toctree:: :maxdepth: 1 - /variable/CMAKE_COMPILER_IS_GNULANG + /variable/CMAKE_COMPILER_IS_GNUCC + /variable/CMAKE_COMPILER_IS_GNUCXX + /variable/CMAKE_COMPILER_IS_GNUG77 /variable/CMAKE_C_COMPILE_FEATURES /variable/CMAKE_C_EXTENSIONS /variable/CMAKE_C_STANDARD diff --git a/Help/manual/cmake.1.rst b/Help/manual/cmake.1.rst index 2ccc6be..063aea1 100644 --- a/Help/manual/cmake.1.rst +++ b/Help/manual/cmake.1.rst @@ -273,6 +273,9 @@ Available commands are: ``rename <oldname> <newname>`` Rename a file or directory (on one volume). +``server`` + Launch :manual:`cmake-server(7)` mode. + ``sleep <number>...`` Sleep for given number of seconds. diff --git a/Help/prop_dir/BINARY_DIR.rst b/Help/prop_dir/BINARY_DIR.rst new file mode 100644 index 0000000..597c79a --- /dev/null +++ b/Help/prop_dir/BINARY_DIR.rst @@ -0,0 +1,5 @@ +BINARY_DIR +---------- + +This read-only directory property reports absolute path to the binary +directory corresponding to the source on which it is read. diff --git a/Help/prop_dir/BUILDSYSTEM_TARGETS.rst b/Help/prop_dir/BUILDSYSTEM_TARGETS.rst new file mode 100644 index 0000000..da907cb --- /dev/null +++ b/Help/prop_dir/BUILDSYSTEM_TARGETS.rst @@ -0,0 +1,11 @@ +BUILDSYSTEM_TARGETS +------------------- + +This read-only directory property contains a +:ref:`;-list <CMake Language Lists>` of buildsystem targets added in the +directory by calls to the :command:`add_library`, :command:`add_executable`, +and :command:`add_custom_target` commands. The list does not include any +:ref:`Imported Targets` or :ref:`Alias Targets`, but does include +:ref:`Interface Libraries`. Each entry in the list is the logical name +of a target, suitable to pass to the :command:`get_property` command +``TARGET`` option. diff --git a/Help/prop_dir/SOURCE_DIR.rst b/Help/prop_dir/SOURCE_DIR.rst new file mode 100644 index 0000000..ac98c3b --- /dev/null +++ b/Help/prop_dir/SOURCE_DIR.rst @@ -0,0 +1,5 @@ +SOURCE_DIR +---------- + +This read-only directory property reports absolute path to the source +directory on which it is read. diff --git a/Help/prop_dir/SUBDIRECTORIES.rst b/Help/prop_dir/SUBDIRECTORIES.rst new file mode 100644 index 0000000..2c2ea77 --- /dev/null +++ b/Help/prop_dir/SUBDIRECTORIES.rst @@ -0,0 +1,15 @@ +SUBDIRECTORIES +-------------- + +This read-only directory property contains a +:ref:`;-list <CMake Language Lists>` of subdirectories processed so far by +the :command:`add_subdirectory` or :command:`subdirs` commands. Each entry is +the absolute path to the source directory (containing the ``CMakeLists.txt`` +file). This is suitable to pass to the :command:`get_property` command +``DIRECTORY`` option. + +.. note:: + + The :command:`subdirs` command does not process its arguments until + after the calling directory is fully processed. Therefore looking + up this property in the current directory will not see them. diff --git a/Help/release/dev/ExternalProject-HTTP_HEADER.rst b/Help/release/dev/ExternalProject-HTTP_HEADER.rst new file mode 100644 index 0000000..927d1b2 --- /dev/null +++ b/Help/release/dev/ExternalProject-HTTP_HEADER.rst @@ -0,0 +1,5 @@ +ExternalProject-HTTP_HEADER +--------------------------- + +* The :module:`ExternalProject` module gained a ``HTTP_HEADER`` + option to add http download headers. diff --git a/Help/release/dev/ExternalProject-http-credentials.rst b/Help/release/dev/ExternalProject-http-credentials.rst new file mode 100644 index 0000000..e3a362a --- /dev/null +++ b/Help/release/dev/ExternalProject-http-credentials.rst @@ -0,0 +1,5 @@ +ExternalProject-http-credentials +-------------------------------- + +* The :module:`ExternalProject` module gained ``HTTP_USERNAME`` and + ``HTTP_PASSWORD`` options to set http download credentials. diff --git a/Help/release/dev/add_androidmk_generator.rst b/Help/release/dev/add_androidmk_generator.rst new file mode 100644 index 0000000..dd7867c --- /dev/null +++ b/Help/release/dev/add_androidmk_generator.rst @@ -0,0 +1,10 @@ +add_androidmk_generator +----------------------- + +* The :command:`install` command gained an ``EXPORT_ANDROID_MK`` + subcommand to install ``Android.mk`` files referencing installed + libraries as prebuilts for the Android NDK build system. + +* The :command:`export` command gained an ``ANDROID_MK`` option + to generate ``Android.mk`` files referencing CMake-built + libraries as prebuilts for the Android NDK build system. diff --git a/Help/release/dev/cmake-gui-open-project.rst b/Help/release/dev/cmake-gui-open-project.rst new file mode 100644 index 0000000..32f0f0f --- /dev/null +++ b/Help/release/dev/cmake-gui-open-project.rst @@ -0,0 +1,5 @@ +cmake-gui-open-project +---------------------- + +* :manual:`cmake-gui(1)` gained a button to open the generated project file + for :ref:`Visual Studio Generators` and the :generator:`Xcode` generator. diff --git a/Help/release/dev/cmake-server-basic.rst b/Help/release/dev/cmake-server-basic.rst new file mode 100644 index 0000000..0b97660 --- /dev/null +++ b/Help/release/dev/cmake-server-basic.rst @@ -0,0 +1,6 @@ +cmake-server-basic +------------------ + +* A new :manual:`cmake-server(7)` mode was added to provide semantic + information about a CMake-generated buildsystem to clients through + a JSON protocol. diff --git a/Help/release/dev/cpack-rpm-srpm-package.rst b/Help/release/dev/cpack-rpm-srpm-package.rst new file mode 100644 index 0000000..803b9fc --- /dev/null +++ b/Help/release/dev/cpack-rpm-srpm-package.rst @@ -0,0 +1,7 @@ +cpack-rpm-srpm-package +---------------------- + +* The :module:`CPackRPM` module learned to generate source rpm + (SRPM) packages on demand. See :variable:`CPACK_RPM_PACKAGE_SOURCES`, + :variable:`CPACK_RPM_SOURCE_PKG_BUILD_PARAMS` and + :variable:`CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX`. diff --git a/Help/release/dev/cpack.hash_computing.rst b/Help/release/dev/cpack.hash_computing.rst new file mode 100644 index 0000000..9780bb2 --- /dev/null +++ b/Help/release/dev/cpack.hash_computing.rst @@ -0,0 +1,5 @@ +cpack.hash_computing +-------------------- + +* CPack gained a new :variable:`CPACK_PACKAGE_CHECKSUM` variable to + enable generation of a checksum file for each package file. diff --git a/Help/release/dev/directory-list-targets-and-subdirs.rst b/Help/release/dev/directory-list-targets-and-subdirs.rst new file mode 100644 index 0000000..85f2c82 --- /dev/null +++ b/Help/release/dev/directory-list-targets-and-subdirs.rst @@ -0,0 +1,16 @@ +directory-list-targets-and-subdirs +---------------------------------- + +* A :prop_dir:`SOURCE_DIR` directory property was added to get the + absolute path to the source directory associated with a directory. + +* A :prop_dir:`BINARY_DIR` directory property was added to get the + absolute path to the binary directory corresponding to the source + directory on which the property is read. + +* A :prop_dir:`BUILDSYSTEM_TARGETS` directory property was added to + get the list of logical buildsystem target names added by the + project in a directory. + +* A :prop_dir:`SUBDIRECTORIES` directory property was added to + get the list of subdirectories added by a project in a directory. diff --git a/Help/release/dev/file-curl-httpheader.rst b/Help/release/dev/file-curl-httpheader.rst new file mode 100644 index 0000000..2147d40 --- /dev/null +++ b/Help/release/dev/file-curl-httpheader.rst @@ -0,0 +1,5 @@ +file-curl-httpheader +-------------------- + +* The :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands + gained a ``HTTPHEADER <HTTP-header>`` option. diff --git a/Help/release/dev/file-curl-userpw.rst b/Help/release/dev/file-curl-userpw.rst new file mode 100644 index 0000000..4ae1fee --- /dev/null +++ b/Help/release/dev/file-curl-userpw.rst @@ -0,0 +1,5 @@ +file-curl-userpw +---------------- + +* The :command:`file(DOWNLOAD)` and :command:`file(UPLOAD)` commands + gained a ``USERPWD <username>:<password>`` option. diff --git a/Help/release/dev/find_package-dir-sort.rst b/Help/release/dev/find_package-dir-sort.rst new file mode 100644 index 0000000..67b93eb --- /dev/null +++ b/Help/release/dev/find_package-dir-sort.rst @@ -0,0 +1,13 @@ +find_package-dir-sort +--------------------- + +* The :command:`find_package` command gained the possibility of + sorting compatible libraries by ``NAME`` or by ``NATURAL`` sorting by + setting the two new variables :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` + and :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION`. + +* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` was added to control + the sorting mode of the :command:`find_package` command. + +* Variable :variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` was added to control + the sorting direction the :command:`find_package` command. diff --git a/Help/release/dev/fortran-submodules.rst b/Help/release/dev/fortran-submodules.rst new file mode 100644 index 0000000..e4e9657 --- /dev/null +++ b/Help/release/dev/fortran-submodules.rst @@ -0,0 +1,7 @@ +fortran-submodules +------------------ + +* The Fortran dependency scanner learned to support the syntax of + `Fortran Submodules`_. + +.. _`Fortran Submodules`: http://fortranwiki.org/fortran/show/Submodules diff --git a/Help/release/dev/ifw-package-resources.rst b/Help/release/dev/ifw-package-resources.rst new file mode 100644 index 0000000..28ea5c4 --- /dev/null +++ b/Help/release/dev/ifw-package-resources.rst @@ -0,0 +1,6 @@ +ifw-package-resources +--------------------- + +* The :module:`CPackIFW` module gained a new + :command:`cpack_ifw_add_package_resources` command to include additional + resources in the installer binary. diff --git a/Help/release/dev/ifw-user-interfaces.rst b/Help/release/dev/ifw-user-interfaces.rst new file mode 100644 index 0000000..26e241a --- /dev/null +++ b/Help/release/dev/ifw-user-interfaces.rst @@ -0,0 +1,7 @@ +ifw-user-interfaces +------------------- + +* The :module:`CPackIFW` module :command:`cpack_ifw_configure_component` and + :command:`cpack_ifw_configure_component_group` commands gained a new + ``USER_INTERFACES`` option to add a list of additonal pages to the IFW + installer. diff --git a/Help/release/dev/timestamp-names.rst b/Help/release/dev/timestamp-names.rst new file mode 100644 index 0000000..ea54b5c --- /dev/null +++ b/Help/release/dev/timestamp-names.rst @@ -0,0 +1,6 @@ +timestamp-names +--------------- + +* The :command:`string(TIMESTAMP)` and :command:`file(TIMESTAMP)` + commands gained support for the ``%a`` and ``%b`` placeholders. + These are the abbreviated weekday and month names. diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst b/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst new file mode 100644 index 0000000..a40667e --- /dev/null +++ b/Help/variable/CMAKE_COMPILER_IS_GNUCC.rst @@ -0,0 +1,5 @@ +CMAKE_COMPILER_IS_GNUCC +----------------------- + +True if the ``C`` compiler is GNU. +Use :variable:`CMAKE_C_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead. diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst b/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst new file mode 100644 index 0000000..f1f5cf7 --- /dev/null +++ b/Help/variable/CMAKE_COMPILER_IS_GNUCXX.rst @@ -0,0 +1,5 @@ +CMAKE_COMPILER_IS_GNUCXX +------------------------ + +True if the C++ (``CXX``) compiler is GNU. +Use :variable:`CMAKE_CXX_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead. diff --git a/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst b/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst new file mode 100644 index 0000000..3d6dab4 --- /dev/null +++ b/Help/variable/CMAKE_COMPILER_IS_GNUG77.rst @@ -0,0 +1,5 @@ +CMAKE_COMPILER_IS_GNUG77 +------------------------ + +True if the ``Fortran`` compiler is GNU. +Use :variable:`CMAKE_Fortran_COMPILER_ID <CMAKE_<LANG>_COMPILER_ID>` instead. diff --git a/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst b/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst deleted file mode 100644 index 4b652c0..0000000 --- a/Help/variable/CMAKE_COMPILER_IS_GNULANG.rst +++ /dev/null @@ -1,15 +0,0 @@ -CMAKE_COMPILER_IS_GNU<LANG> ---------------------------- - -True if the compiler is GNU. - -If the selected ``<LANG>`` compiler is the GNU compiler then this is ``TRUE``, -if not it is ``FALSE``. Unlike the other per-language variables, this -uses the GNU syntax for identifying languages instead of the CMake -syntax. Recognized values of the ``<LANG>`` suffix are: - -:: - - CC = C compiler - CXX = C++ compiler - G77 = Fortran compiler diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst new file mode 100644 index 0000000..99e4ec1 --- /dev/null +++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_DIRECTION.rst @@ -0,0 +1,16 @@ +CMAKE_FIND_PACKAGE_SORT_DIRECTION +--------------------------------- + +The sorting direction used by :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER`. +It can assume one of the following values: + +``DEC`` + Default. Ordering is done in descending mode. + The highest folder found will be tested first. + +``ASC`` + Ordering is done in ascending mode. + The lowest folder found will be tested first. + +If :variable:`CMAKE_FIND_PACKAGE_SORT_ORDER` is not set or is set to ``NONE`` +this variable has no effect. diff --git a/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst new file mode 100644 index 0000000..ba5f3a8 --- /dev/null +++ b/Help/variable/CMAKE_FIND_PACKAGE_SORT_ORDER.rst @@ -0,0 +1,36 @@ +CMAKE_FIND_PACKAGE_SORT_ORDER +----------------------------- + +The default order for sorting packages found using :command:`find_package`. +It can assume one of the following values: + +``NONE`` + Default. No attempt is done to sort packages. + The first valid package found will be selected. + +``NAME`` + Sort packages lexicographically before selecting one. + +``NATURAL`` + Sort packages using natural order (see ``strverscmp(3)`` manual), + i.e. such that contiguous digits are compared as whole numbers. + +Natural sorting can be employed to return the highest version when multiple +versions of the same library are found by :command:`find_package`. For +example suppose that the following libraries have been found: + +* libX-1.1.0 +* libX-1.2.9 +* libX-1.2.10 + +By setting ``NATURAL`` order we can select the one with the highest +version number ``libX-1.2.10``. + +.. code-block:: cmake + + set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) + find_package(libX CONFIG) + +The sort direction can be controlled using the +:variable:`CMAKE_FIND_PACKAGE_SORT_DIRECTION` variable +(by default decrescent, e.g. lib-B will be tested before lib-A). diff --git a/Modules/CPack.cmake b/Modules/CPack.cmake index 675b38b..99f22ec 100644 --- a/Modules/CPack.cmake +++ b/Modules/CPack.cmake @@ -116,6 +116,15 @@ # A branding image that will be displayed inside the installer (used by GUI # installers). # +# .. variable:: CPACK_PACKAGE_CHECKSUM +# +# An algorithm that will be used to generate additional file with checksum +# of the package. Output file name will be:: +# +# ${CPACK_PACKAGE_FILE_NAME}.${CPACK_PACKAGE_CHECKSUM} +# +# Current supported alogorithms: MD5|SHA1|SHA224|SHA256|SHA384|SHA512. +# # .. variable:: CPACK_PROJECT_CONFIG_FILE # # CPack-time project CPack configuration file. This file included at cpack @@ -502,6 +511,7 @@ if(NOT CPACK_SOURCE_GENERATOR) if(CYGWIN) option(CPACK_SOURCE_CYGWIN "Enable to build Cygwin source packages" ON) else() + option(CPACK_SOURCE_RPM "Enable to build RPM source packages" OFF) option(CPACK_SOURCE_TBZ2 "Enable to build TBZ2 source packages" ON) option(CPACK_SOURCE_TGZ "Enable to build TGZ source packages" ON) option(CPACK_SOURCE_TXZ "Enable to build TXZ source packages" ON) @@ -515,6 +525,7 @@ if(NOT CPACK_SOURCE_GENERATOR) cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_7Z 7Z) cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_CYGWIN CygwinSource) + cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_RPM RPM) cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TBZ2 TBZ2) cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TGZ TGZ) cpack_optional_append(CPACK_SOURCE_GENERATOR CPACK_SOURCE_TXZ TXZ) @@ -544,6 +555,7 @@ mark_as_advanced( CPACK_BINARY_ZIP CPACK_SOURCE_7Z CPACK_SOURCE_CYGWIN + CPACK_SOURCE_RPM CPACK_SOURCE_TBZ2 CPACK_SOURCE_TGZ CPACK_SOURCE_TXZ @@ -651,6 +663,8 @@ set(CPACK_PACKAGE_FILE_NAME "${CPACK_SOURCE_PACKAGE_FILE_NAME}") set(CPACK_IGNORE_FILES "${CPACK_SOURCE_IGNORE_FILES}") set(CPACK_STRIP_FILES "${CPACK_SOURCE_STRIP_FILES}") +set(CPACK_RPM_PACKAGE_SOURCES "ON") + cpack_encode_variables() configure_file("${cpack_source_input_file}" "${CPACK_SOURCE_OUTPUT_CONFIG_FILE}" @ONLY) diff --git a/Modules/CPackIFW.cmake b/Modules/CPackIFW.cmake index ebc5c90..bb1285d 100644 --- a/Modules/CPackIFW.cmake +++ b/Modules/CPackIFW.cmake @@ -131,6 +131,14 @@ # # Filename for a custom installer control script. # +# .. variable:: CPACK_IFW_PACKAGE_RESOURCES +# +# List of additional resources ('.qrc' files) to include in the installer +# binary. +# +# You can use :command:`cpack_ifw_add_package_resources` command to resolve +# relative paths. +# # .. variable:: CPACK_IFW_REPOSITORIES_ALL # # The list of remote repositories. @@ -181,136 +189,174 @@ # # The module defines the following commands: # -# -------------------------------------------------------------------------- -# # .. command:: cpack_ifw_configure_component # -# Sets the arguments specific to the CPack IFW generator. +# Sets the arguments specific to the CPack IFW generator. +# +# :: # -# :: +# cpack_ifw_configure_component(<compname> [COMMON] [ESSENTIAL] +# [NAME <name>] +# [VERSION <version>] +# [SCRIPT <script>] +# [PRIORITY <priority>] +# [DEPENDS <com_id> ...] +# [LICENSES <display_name> <file_path> ...] +# [USER_INTERFACES <file_path> <file_path> ...]) # -# cpack_ifw_configure_component(<compname> [COMMON] [ESSENTIAL] -# [NAME <name>] -# [VERSION <version>] -# [SCRIPT <script>] -# [PRIORITY <priority>] -# [DEPENDS <com_id> ...] -# [LICENSES <display_name> <file_path> ...]) +# This command should be called after :command:`cpack_add_component` command. # -# This command should be called after :command:`cpack_add_component` command. +# ``COMMON`` +# if set, then the component will be packaged and installed as part +# of a group to which it belongs. # -# ``COMMON`` if set, then the component will be packaged and installed as part -# of a group to which it belongs. +# ``ESSENTIAL`` +# if set, then the package manager stays disabled until that +# component is updated. # -# ``ESSENTIAL`` if set, then the package manager stays disabled until that -# component is updated. +# ``NAME`` +# is used to create domain-like identification for this component. +# By default used origin component name. # -# ``NAME`` is used to create domain-like identification for this component. -# By default used origin component name. +# ``VERSION`` +# is version of component. +# By default used :variable:`CPACK_PACKAGE_VERSION`. # -# ``VERSION`` is version of component. -# By default used :variable:`CPACK_PACKAGE_VERSION`. +# ``SCRIPT`` +# is a relative or absolute path to operations script +# for this component. # -# ``SCRIPT`` is a relative or absolute path to operations script -# for this component. +# ``PRIORITY`` +# is priority of the component in the tree. # -# ``PRIORITY`` is priority of the component in the tree. +# ``DEPENDS`` +# list of dependency component identifiers in QtIFW_ style. # -# ``DEPENDS`` list of dependency component identifiers in QtIFW_ style. +# ``LICENSES`` +# pair of <display_name> and <file_path> of license text for this +# component. You can specify more then one license. # -# ``LICENSES`` pair of <display_name> and <file_path> of license text for this -# component. You can specify more then one license. +# ``USER_INTERFACES`` +# a list of <file_path> representing pages to load # -# -------------------------------------------------------------------------- # # .. command:: cpack_ifw_configure_component_group # -# Sets the arguments specific to the CPack IFW generator. +# Sets the arguments specific to the CPack IFW generator. # -# :: +# :: # -# cpack_ifw_configure_component_group(<groupname> -# [NAME <name>] -# [VERSION <version>] -# [SCRIPT <script>] -# [PRIORITY <priority>] -# [LICENSES <display_name> <file_path> ...]) +# cpack_ifw_configure_component_group(<groupname> +# [NAME <name>] +# [VERSION <version>] +# [SCRIPT <script>] +# [PRIORITY <priority>] +# [LICENSES <display_name> <file_path> ...] +# [USER_INTERFACES <file_path> <file_path> ...]) # -# This command should be called after :command:`cpack_add_component_group` -# command. +# This command should be called after :command:`cpack_add_component_group` +# command. # -# ``NAME`` is used to create domain-like identification for this component -# group. -# By default used origin component group name. +# ``NAME`` +# is used to create domain-like identification for this component group. +# By default used origin component group name. # -# ``VERSION`` is version of component group. -# By default used :variable:`CPACK_PACKAGE_VERSION`. +# ``VERSION`` +# is version of component group. +# By default used :variable:`CPACK_PACKAGE_VERSION`. # -# ``SCRIPT`` is a relative or absolute path to operations script -# for this component group. +# ``SCRIPT`` +# is a relative or absolute path to operations script +# for this component group. # -# ``PRIORITY`` is priority of the component group in the tree. +# ``PRIORITY`` +# is priority of the component group in the tree. # -# ``LICENSES`` pair of <display_name> and <file_path> of license text for this -# component group. You can specify more then one license. +# ``LICENSES`` +# pair of <display_name> and <file_path> of license text for this +# component group. You can specify more then one license. # -# -------------------------------------------------------------------------- +# ``USER_INTERFACES`` +# a list of <file_path> representing pages to load # -# .. command:: cpack_ifw_add_repository # -# Add QtIFW_ specific remote repository to binary installer. +# .. command:: cpack_ifw_add_repository # -# :: +# Add QtIFW_ specific remote repository to binary installer. # -# cpack_ifw_add_repository(<reponame> [DISABLED] -# URL <url> -# [USERNAME <username>] -# [PASSWORD <password>] -# [DISPLAY_NAME <display_name>]) +# :: # -# This command will also add the <reponame> repository -# to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`. +# cpack_ifw_add_repository(<reponame> [DISABLED] +# URL <url> +# [USERNAME <username>] +# [PASSWORD <password>] +# [DISPLAY_NAME <display_name>]) # -# ``DISABLED`` if set, then the repository will be disabled by default. +# This command will also add the <reponame> repository +# to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`. # -# ``URL`` is points to a list of available components. +# ``DISABLED`` +# if set, then the repository will be disabled by default. # -# ``USERNAME`` is used as user on a protected repository. +# ``URL`` +# is points to a list of available components. # -# ``PASSWORD`` is password to use on a protected repository. +# ``USERNAME`` +# is used as user on a protected repository. # -# ``DISPLAY_NAME`` is string to display instead of the URL. +# ``PASSWORD`` +# is password to use on a protected repository. # +# ``DISPLAY_NAME`` +# is string to display instead of the URL. # -# -------------------------------------------------------------------------- # # .. command:: cpack_ifw_update_repository # -# Update QtIFW_ specific repository from remote repository. +# Update QtIFW_ specific repository from remote repository. +# +# :: +# +# cpack_ifw_update_repository(<reponame> +# [[ADD|REMOVE] URL <url>]| +# [REPLACE OLD_URL <old_url> NEW_URL <new_url>]] +# [USERNAME <username>] +# [PASSWORD <password>] +# [DISPLAY_NAME <display_name>]) +# +# This command will also add the <reponame> repository +# to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`. +# +# ``URL`` +# is points to a list of available components. +# +# ``OLD_URL`` +# is points to a list that will replaced. # -# :: +# ``NEW_URL`` +# is points to a list that will replace to. # -# cpack_ifw_update_repository(<reponame> -# [[ADD|REMOVE] URL <url>]| -# [REPLACE OLD_URL <old_url> NEW_URL <new_url>]] -# [USERNAME <username>] -# [PASSWORD <password>] -# [DISPLAY_NAME <display_name>]) +# ``USERNAME`` +# is used as user on a protected repository. # -# This command will also add the <reponame> repository -# to a variable :variable:`CPACK_IFW_REPOSITORIES_ALL`. +# ``PASSWORD`` +# is password to use on a protected repository. # -# ``URL`` is points to a list of available components. +# ``DISPLAY_NAME`` +# is string to display instead of the URL. # -# ``OLD_URL`` is points to a list that will replaced. # -# ``NEW_URL`` is points to a list that will replace to. +# .. command:: cpack_ifw_add_package_resources # -# ``USERNAME`` is used as user on a protected repository. +# Add additional resources in the installer binary. # -# ``PASSWORD`` is password to use on a protected repository. +# :: +# +# cpack_ifw_add_package_resources(<file_path> <file_path> ...) +# +# This command will also add the specified files +# to a variable :variable:`CPACK_IFW_PACKAGE_RESOURCES`. # -# ``DISPLAY_NAME`` is string to display instead of the URL. # # Example usage # ^^^^^^^^^^^^^ @@ -362,16 +408,16 @@ # # Qt Installer Framework Manual: # -# Index page +# * Index page: # http://doc.qt.io/qtinstallerframework/index.html # -# Component Scripting +# * Component Scripting: # http://doc.qt.io/qtinstallerframework/scripting.html # -# Predefined Variables +# * Predefined Variables: # http://doc.qt.io/qtinstallerframework/scripting.html#predefined-variables # -# Promoting Updates +# * Promoting Updates: # http://doc.qt.io/qtinstallerframework/ifw-updates.html # # Download Qt Installer Framework for you platform from Qt site: @@ -543,6 +589,22 @@ macro(_cpack_ifw_resolve_lisenses _variable) endif() endmacro() +# Resolve full path to a list of provided files +macro(_cpack_ifw_resolve_file_list _variable) + if(${_variable}) + set(_ifw_list_fix) + foreach(_ifw_file_arg ${${_variable}}) + get_filename_component(_ifw_file_arg "${_ifw_file_arg}" ABSOLUTE) + if(EXISTS ${_ifw_file_arg}) + list(APPEND _ifw_list_fix "${_ifw_file_arg}") + else() + message(WARNING "CPack IFW: page file \"${_ifw_file_arg}\" does not exist. Skipping") + endif() + endforeach(_ifw_file_arg) + set(${_variable} "${_ifw_list_fix}") + endif() +endmacro() + # Macro for configure component macro(cpack_ifw_configure_component compname) @@ -550,11 +612,12 @@ macro(cpack_ifw_configure_component compname) set(_IFW_OPT COMMON ESSENTIAL) set(_IFW_ARGS NAME VERSION SCRIPT PRIORITY) - set(_IFW_MULTI_ARGS DEPENDS LICENSES) + set(_IFW_MULTI_ARGS DEPENDS LICENSES USER_INTERFACES) cmake_parse_arguments(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN}) _cpack_ifw_resolve_script(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_SCRIPT) _cpack_ifw_resolve_lisenses(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_LICENSES) + _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_${_CPACK_IFWCOMP_UNAME}_USER_INTERFACES) set(_CPACK_IFWCOMP_STR "\n# Configuration for IFW component \"${compname}\"\n") @@ -589,11 +652,12 @@ macro(cpack_ifw_configure_component_group grpname) set(_IFW_OPT) set(_IFW_ARGS NAME VERSION SCRIPT PRIORITY) - set(_IFW_MULTI_ARGS LICENSES) + set(_IFW_MULTI_ARGS LICENSES USER_INTERFACES) cmake_parse_arguments(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME} "${_IFW_OPT}" "${_IFW_ARGS}" "${_IFW_MULTI_ARGS}" ${ARGN}) _cpack_ifw_resolve_script(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_SCRIPT) _cpack_ifw_resolve_lisenses(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_LICENSES) + _cpack_ifw_resolve_file_list(CPACK_IFW_COMPONENT_GROUP_${_CPACK_IFWGRP_UNAME}_USER_INTERFACES) set(_CPACK_IFWGRP_STR "\n# Configuration for IFW component group \"${grpname}\"\n") @@ -698,6 +762,17 @@ macro(cpack_ifw_update_repository reponame) endmacro() +# Macro for adding resources +macro(cpack_ifw_add_package_resources) + set(_CPACK_IFW_PACKAGE_RESOURCES ${ARGV}) + _cpack_ifw_resolve_file_list(_CPACK_IFW_PACKAGE_RESOURCES) + list(APPEND CPACK_IFW_PACKAGE_RESOURCES ${_CPACK_IFW_PACKAGE_RESOURCES}) + set(_CPACK_IFWQRC_STR "list(APPEND CPACK_IFW_PACKAGE_RESOURCES \"${_CPACK_IFW_PACKAGE_RESOURCES}\")\n") + if(CPack_CMake_INCLUDED) + file(APPEND "${CPACK_OUTPUT_CONFIG_FILE}" "${_CPACK_IFWQRC_STR}") + endif() +endmacro() + # Resolve package control script _cpack_ifw_resolve_script(CPACK_IFW_PACKAGE_CONTROL_SCRIPT) diff --git a/Modules/CPackRPM.cmake b/Modules/CPackRPM.cmake index 36caac6..d78f7fa 100644 --- a/Modules/CPackRPM.cmake +++ b/Modules/CPackRPM.cmake @@ -706,6 +706,77 @@ # symbolic link(s) is also on a relocatable path, relocating it during # package installation may cause initial symbolic link to point to an # invalid location. +# +# Packaging of sources (SRPM) +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# SRPM packaging is enabled by setting :variable:`CPACK_RPM_PACKAGE_SOURCES` +# variable while usually using :variable:`CPACK_INSTALLED_DIRECTORIES` variable +# to provide directory containing CMakeLists.txt and source files. +# +# For CMake projects SRPM package would be product by executing: +# +# ``cpack -G RPM --config ./CPackSourceConfig.cmake`` +# +# .. note:: +# +# Produced SRPM package is expected to be built with :manual:`cmake(1)` executable +# and packaged with :manual:`cpack(1)` executable so CMakeLists.txt has to be +# located in root source directory and must be able to generate binary rpm +# packages by executing ``cpack -G`` command. The two executables as well as +# rpmbuild must also be present when generating binary rpm packages from the +# produced SRPM package. +# +# Once the SRPM package is generated it can be used to generate binary packages +# by creating a directory structure for rpm generation and executing rpmbuild +# tool: +# +# ``mkdir -p build_dir/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}`` +# ``rpmbuild --define "_topdir <path_to_build_dir>" --rebuild <SRPM_file_name>`` +# +# Generated packages will be located in build_dir/RPMS directory or its sub +# directories. +# +# .. note:: +# +# SRPM package internally uses CPack/RPM generator to generate binary packages +# so CMakeScripts.txt can decide during the SRPM to binary rpm generation step +# what content the package(s) should have as well as how they should be packaged +# (monolithic or components). CMake can decide this for e.g. by reading environment +# variables set by the package manager before starting the process of generating +# binary rpm packages. This way a single SRPM package can be used to produce +# different binary rpm packages on different platforms depending on the platform's +# packaging rules. +# +# Source RPM packaging has it's own set of variables: +# +# .. variable:: CPACK_RPM_PACKAGE_SOURCES +# +# Should the content be packaged as a source rpm (default is binary rpm). +# +# * Mandatory : NO +# * Default : OFF +# +# .. note:: +# +# For cmake projects :variable:`CPACK_RPM_PACKAGE_SOURCES` variable is set +# to ``OFF`` in CPackConfig.cmake and ``ON`` in CPackSourceConfig.cmake +# generated files. +# +# .. variable:: CPACK_RPM_SOURCE_PKG_BUILD_PARAMS +# +# Additional command-line parameters provided to :manual:`cmake(1)` executable. +# +# * Mandatory : NO +# * Default : - +# +# .. variable:: CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX +# +# Packaging install prefix that would be provided in :variable:`CPACK_PACKAGING_INSTALL_PREFIX` +# variable for producing binary RPM packages. +# +# * Mandatory : YES +# * Default : "/" #============================================================================= # Copyright 2007-2016 Kitware, Inc. @@ -847,7 +918,10 @@ function(cpack_rpm_prepare_content_list) set(_DISTINCT_PATH "${_RPM_RELOCATION_PREFIX}") string(REPLACE "/" ";" _CPACK_RPM_PACKAGE_PREFIX_ELEMS " ${_RPM_RELOCATION_PREFIX}") - list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1) + cmake_policy(PUSH) + cmake_policy(SET CMP0007 NEW) + list(REMOVE_AT _CPACK_RPM_PACKAGE_PREFIX_ELEMS -1) + cmake_policy(POP) unset(_TMP_LIST) # Now generate all of the parent dirs of the relocation path foreach(_PREFIX_PATH_ELEM ${_CPACK_RPM_PACKAGE_PREFIX_ELEMS}) @@ -1515,18 +1589,27 @@ function(cpack_rpm_generate_package) set(CPACK_RPM_COMPRESSION_TYPE_TMP "") endif() - if(CPACK_PACKAGE_RELOCATABLE OR CPACK_RPM_PACKAGE_RELOCATABLE) - if(CPACK_RPM_PACKAGE_DEBUG) - message("CPackRPM:Debug: Trying to build a relocatable package") + if(NOT CPACK_RPM_PACKAGE_SOURCES) + if(CPACK_PACKAGE_RELOCATABLE OR CPACK_RPM_PACKAGE_RELOCATABLE) + if(CPACK_RPM_PACKAGE_DEBUG) + message("CPackRPM:Debug: Trying to build a relocatable package") + endif() + if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON")) + message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.") + set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE) + else() + set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files) + cpack_rpm_prepare_relocation_paths() + set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE) + endif() endif() - if(CPACK_SET_DESTDIR AND (NOT CPACK_SET_DESTDIR STREQUAL "I_ON")) - message("CPackRPM:Warning: CPACK_SET_DESTDIR is set (=${CPACK_SET_DESTDIR}) while requesting a relocatable package (CPACK_RPM_PACKAGE_RELOCATABLE is set): this is not supported, the package won't be relocatable.") - set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE) - else() - set(CPACK_RPM_PACKAGE_PREFIX ${CPACK_PACKAGING_INSTALL_PREFIX}) # kept for back compatibility (provided external RPM spec files) - cpack_rpm_prepare_relocation_paths() - set(CPACK_RPM_PACKAGE_RELOCATABLE TRUE) + else() + if(CPACK_RPM_PACKAGE_COMPONENT) + message(FATAL_ERROR "CPACK_RPM_PACKAGE_SOURCES parameter can not be used" + " in combination with CPACK_RPM_PACKAGE_COMPONENT parameter!") endif() + + set(CPACK_RPM_PACKAGE_RELOCATABLE FALSE) # disable relocatable option if building source RPM endif() # Check if additional fields for RPM spec header are given @@ -1870,13 +1953,50 @@ function(cpack_rpm_generate_package) endif() endif() - # We should generate a USER spec file template: - # - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE - # - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE - if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE) + if(CPACK_RPM_PACKAGE_SOURCES) # source rpm + set(archive_name_ "${CPACK_RPM_PACKAGE_NAME}-${CPACK_RPM_PACKAGE_VERSION}") + + execute_process( + COMMAND ${CMAKE_COMMAND} -E tar "cfvz" "${CPACK_RPM_DIRECTORY}/SOURCES/${archive_name_}.tar.gz" "${CPACK_PACKAGE_FILE_NAME}" + WORKING_DIRECTORY ${CPACK_RPM_DIRECTORY} + ) + set(TMP_RPM_SOURCE "Source: ${archive_name_}.tar.gz") + + if(CPACK_RPM_BUILDREQUIRES) + set(TMP_RPM_BUILD_REQUIRES "BuildRequires: ${CPACK_RPM_BUILDREQUIRES}") + endif() + + # Disable debuginfo packages - srpm generates invalid packages due to + # releasing controll to cpack to generate binary packages. + # Note however that this doesn't prevent cpack to generate debuginfo + # packages when run from srpm with --rebuild. + set(TMP_RPM_DISABLE_DEBUGINFO "%define debug_package %{nil}") + + if(NOT CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX) + set(CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX "/") + endif() + + set(TMP_RPM_BUILD + " +%build +mkdir cpack_rpm_build_dir +cd cpack_rpm_build_dir +cmake ${CPACK_RPM_SOURCE_PKG_BUILD_PARAMS} -DCPACK_PACKAGING_INSTALL_PREFIX=${CPACK_RPM_SOURCE_PKG_PACKAGING_INSTALL_PREFIX} ../${CPACK_PACKAGE_FILE_NAME} +make %{?_smp_mflags}" # %{?_smp_mflags} -> -j option + ) + set(TMP_RPM_INSTALL + " +cd cpack_rpm_build_dir +cpack -G RPM +mv *.rpm %_rpmdir" + ) + set(TMP_RPM_PREP "%setup -c") + + set(RPMBUILD_FLAGS "-bs") + file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in "# -*- rpm-spec -*- -BuildRoot: \@CPACK_RPM_DIRECTORY\@/\@CPACK_PACKAGE_FILE_NAME\@\@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH\@ +BuildRoot: %_topdir/\@CPACK_PACKAGE_FILE_NAME\@ Summary: \@CPACK_RPM_PACKAGE_SUMMARY\@ Name: \@CPACK_RPM_PACKAGE_NAME\@ Version: \@CPACK_RPM_PACKAGE_VERSION\@ @@ -1884,6 +2004,64 @@ Release: \@CPACK_RPM_PACKAGE_RELEASE\@ License: \@CPACK_RPM_PACKAGE_LICENSE\@ Group: \@CPACK_RPM_PACKAGE_GROUP\@ Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@ + +\@TMP_RPM_SOURCE\@ +\@TMP_RPM_BUILD_REQUIRES\@ +\@TMP_RPM_BUILDARCH\@ +\@TMP_RPM_PREFIXES\@ + +\@TMP_RPM_DISABLE_DEBUGINFO\@ + +%define _rpmdir %_topdir/RPMS +%define _srcrpmdir %_topdir/SRPMS +\@FILE_NAME_DEFINE\@ +%define _unpackaged_files_terminate_build 0 +\@TMP_RPM_SPEC_INSTALL_POST\@ +\@CPACK_RPM_SPEC_MORE_DEFINE\@ +\@CPACK_RPM_COMPRESSION_TYPE_TMP\@ + +%description +\@CPACK_RPM_PACKAGE_DESCRIPTION\@ + +# This is a shortcutted spec file generated by CMake RPM generator +# we skip _install step because CPack does that for us. +# We do only save CPack installed tree in _prepr +# and then restore it in build. +%prep +\@TMP_RPM_PREP\@ + +\@TMP_RPM_BUILD\@ + +#p build + +%install +\@TMP_RPM_INSTALL\@ + +%clean + +%changelog +\@CPACK_RPM_SPEC_CHANGELOG\@ +" + ) + else() # binary rpm + + # We should generate a USER spec file template: + # - either because the user asked for it : CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE + # - or the user did not provide one : NOT CPACK_RPM_USER_BINARY_SPECFILE + if(CPACK_RPM_GENERATE_USER_BINARY_SPECFILE_TEMPLATE OR NOT CPACK_RPM_USER_BINARY_SPECFILE) + set(RPMBUILD_FLAGS "-bb") + + file(WRITE ${CPACK_RPM_BINARY_SPECFILE}.in + "# -*- rpm-spec -*- +BuildRoot: %_topdir/\@CPACK_PACKAGE_FILE_NAME\@\@CPACK_RPM_PACKAGE_COMPONENT_PART_PATH\@ +Summary: \@CPACK_RPM_PACKAGE_SUMMARY\@ +Name: \@CPACK_RPM_PACKAGE_NAME\@ +Version: \@CPACK_RPM_PACKAGE_VERSION\@ +Release: \@CPACK_RPM_PACKAGE_RELEASE\@ +License: \@CPACK_RPM_PACKAGE_LICENSE\@ +Group: \@CPACK_RPM_PACKAGE_GROUP\@ +Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@ + \@TMP_RPM_URL\@ \@TMP_RPM_REQUIRES\@ \@TMP_RPM_REQUIRES_PRE\@ @@ -1901,10 +2079,10 @@ Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@ \@TMP_RPM_DEBUGINFO\@ -%define _rpmdir \@CPACK_RPM_DIRECTORY\@ +%define _rpmdir %_topdir/RPMS +%define _srcrpmdir %_topdir/SRPMS \@FILE_NAME_DEFINE\@ %define _unpackaged_files_terminate_build 0 -%define _topdir \@CPACK_RPM_DIRECTORY\@ \@TMP_RPM_SPEC_INSTALL_POST\@ \@CPACK_RPM_SPEC_MORE_DEFINE\@ \@CPACK_RPM_COMPRESSION_TYPE_TMP\@ @@ -1917,16 +2095,14 @@ Vendor: \@CPACK_RPM_PACKAGE_VENDOR\@ # We do only save CPack installed tree in _prepr # and then restore it in build. %prep -mv $RPM_BUILD_ROOT \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" - -#p build +mv $RPM_BUILD_ROOT %_topdir/tmpBBroot %install if [ -e $RPM_BUILD_ROOT ]; then rm -rf $RPM_BUILD_ROOT fi -mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT +mv %_topdir/tmpBBroot $RPM_BUILD_ROOT %clean @@ -1951,7 +2127,10 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT %changelog \@CPACK_RPM_SPEC_CHANGELOG\@ -") +" + ) + endif() + # Stop here if we were asked to only generate a template USER spec file # The generated file may then be used as a template by user who wants # to customize their own spec file. @@ -1977,9 +2156,9 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT if(RPMBUILD_EXECUTABLE) # Now call rpmbuild using the SPECFILE execute_process( - COMMAND "${RPMBUILD_EXECUTABLE}" -bb + COMMAND "${RPMBUILD_EXECUTABLE}" ${RPMBUILD_FLAGS} --define "_topdir ${CPACK_RPM_DIRECTORY}" - --buildroot "${CPACK_RPM_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}" + --buildroot "%_topdir/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}" # TODO should I remove this variable? or change the path? --target "${CPACK_RPM_PACKAGE_ARCHITECTURE}" "${CPACK_RPM_BINARY_SPECFILE}" WORKING_DIRECTORY "${CPACK_TOPLEVEL_DIRECTORY}/${CPACK_PACKAGE_FILE_NAME}${CPACK_RPM_PACKAGE_COMPONENT_PART_PATH}" @@ -2006,7 +2185,8 @@ mv \"\@CPACK_TOPLEVEL_DIRECTORY\@/tmpBBroot\" $RPM_BUILD_ROOT # Tell file(GLOB_RECURSE) not to follow directory symlinks # even if the project does not set this policy to NEW. cmake_policy(SET CMP0009 NEW) - file(GLOB_RECURSE GENERATED_FILES "${CPACK_RPM_DIRECTORY}/*.rpm") + file(GLOB_RECURSE GENERATED_FILES "${CPACK_RPM_DIRECTORY}/RPMS/*.rpm" + "${CPACK_RPM_DIRECTORY}/SRPMS/*.rpm") cmake_policy(POP) if(NOT GENERATED_FILES) diff --git a/Modules/ExternalProject-download.cmake.in b/Modules/ExternalProject-download.cmake.in index 91d74e0..8e39a7e 100644 --- a/Modules/ExternalProject-download.cmake.in +++ b/Modules/ExternalProject-download.cmake.in @@ -135,6 +135,8 @@ foreach(i RANGE ${retry_number}) @TIMEOUT_ARGS@ STATUS status LOG log + @USERPWD_ARGS@ + @HTTP_HEADERS_ARGS@ ) list(GET status 0 status_code) diff --git a/Modules/ExternalProject.cmake b/Modules/ExternalProject.cmake index 5ea309f..79054a1 100644 --- a/Modules/ExternalProject.cmake +++ b/Modules/ExternalProject.cmake @@ -75,6 +75,12 @@ Create custom targets to build projects in external trees Hash of file at URL ``URL_MD5 md5`` Equivalent to URL_HASH MD5=md5 + ``HTTP_USERNAME <username>`` + Username for download operation + ``HTTP_PASSWORD <username>`` + Password for download operation + ``HTTP_HEADER <header>`` + HTTP header for download operation. Suboption can be repeated several times. ``TLS_VERIFY <bool>`` Should certificate for https be checked ``TLS_CAINFO <file>`` @@ -858,7 +864,7 @@ endif() endfunction(_ep_write_gitupdate_script) -function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout no_progress hash tls_verify tls_cainfo) +function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout no_progress hash tls_verify tls_cainfo userpwd http_headers) if(timeout) set(TIMEOUT_ARGS TIMEOUT ${timeout}) set(TIMEOUT_MSG "${timeout} seconds") @@ -906,6 +912,22 @@ function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout no_p set(TLS_CAINFO_CODE "set(CMAKE_TLS_CAINFO \"${tls_cainfo}\")") endif() + if(userpwd STREQUAL ":") + set(USERPWD_ARGS) + else() + set(USERPWD_ARGS USERPWD "${userpwd}") + endif() + + set(HTTP_HEADERS_ARGS "") + if(NOT http_headers STREQUAL "") + foreach(header ${http_headers}) + set( + HTTP_HEADERS_ARGS + "HTTPHEADER \"${header}\"\n ${HTTP_HEADERS_ARGS}" + ) + endforeach() + endif() + # Used variables: # * TLS_VERIFY_CODE # * TLS_CAINFO_CODE @@ -916,6 +938,8 @@ function(_ep_write_downloadfile_script script_filename REMOTE LOCAL timeout no_p # * SHOW_PROGRESS # * TIMEOUT_ARGS # * TIMEOUT_MSG + # * USERPWD_ARGS + # * HTTP_HEADERS_ARGS configure_file( "${_ExternalProject_SELF_DIR}/ExternalProject-download.cmake.in" "${script_filename}" @@ -1919,8 +1943,11 @@ function(_ep_add_download_command name) get_property(no_progress TARGET ${name} PROPERTY _EP_DOWNLOAD_NO_PROGRESS) get_property(tls_verify TARGET ${name} PROPERTY _EP_TLS_VERIFY) get_property(tls_cainfo TARGET ${name} PROPERTY _EP_TLS_CAINFO) + get_property(http_username TARGET ${name} PROPERTY _EP_HTTP_USERNAME) + get_property(http_password TARGET ${name} PROPERTY _EP_HTTP_PASSWORD) + get_property(http_headers TARGET ${name} PROPERTY _EP_HTTP_HEADER) set(download_script "${stamp_dir}/download-${name}.cmake") - _ep_write_downloadfile_script("${download_script}" "${url}" "${file}" "${timeout}" "${no_progress}" "${hash}" "${tls_verify}" "${tls_cainfo}") + _ep_write_downloadfile_script("${download_script}" "${url}" "${file}" "${timeout}" "${no_progress}" "${hash}" "${tls_verify}" "${tls_cainfo}" "${http_username}:${http_password}" "${http_headers}") set(cmd ${CMAKE_COMMAND} -P "${download_script}" COMMAND) if (no_extract) diff --git a/Modules/FeatureSummary.cmake b/Modules/FeatureSummary.cmake index 764a5f7..548d12a 100644 --- a/Modules/FeatureSummary.cmake +++ b/Modules/FeatureSummary.cmake @@ -1,268 +1,27 @@ -#.rst: -# FeatureSummary -# -------------- -# -# Macros for generating a summary of enabled/disabled features -# -# -# -# This module provides the macros feature_summary(), -# set_package_properties() and add_feature_info(). For compatibility it -# also still provides set_package_info(), set_feature_info(), -# print_enabled_features() and print_disabled_features(). -# -# These macros can be used to generate a summary of enabled and disabled -# packages and/or feature for a build tree: -# -# :: -# -# -- The following OPTIONAL packages have been found: -# LibXml2 (required version >= 2.4), XML processing lib, <http://xmlsoft.org> -# * Enables HTML-import in MyWordProcessor -# * Enables odt-export in MyWordProcessor -# PNG , A PNG image library. , <http://www.libpng.org/pub/png/> -# * Enables saving screenshots -# -- The following OPTIONAL packages have not been found: -# Lua51 , The Lua scripting language. , <http://www.lua.org> -# * Enables macros in MyWordProcessor -# Foo , Foo provides cool stuff. -# -# -# -# -# -# :: -# -# FEATURE_SUMMARY( [FILENAME <file>] -# [APPEND] -# [VAR <variable_name>] -# [INCLUDE_QUIET_PACKAGES] -# [FATAL_ON_MISSING_REQUIRED_PACKAGES] -# [DESCRIPTION "Found packages:"] -# WHAT (ALL | PACKAGES_FOUND | PACKAGES_NOT_FOUND -# | ENABLED_FEATURES | DISABLED_FEATURES) -# ) -# -# -# -# The FEATURE_SUMMARY() macro can be used to print information about -# enabled or disabled packages or features of a project. By default, -# only the names of the features/packages will be printed and their -# required version when one was specified. Use SET_PACKAGE_PROPERTIES() -# to add more useful information, like e.g. a download URL for the -# respective package or their purpose in the project. -# -# The WHAT option is the only mandatory option. Here you specify what -# information will be printed: -# -# ``ALL`` -# print everything -# ``ENABLED_FEATURES`` -# the list of all features which are enabled -# ``DISABLED_FEATURES`` -# the list of all features which are disabled -# ``PACKAGES_FOUND`` -# the list of all packages which have been found -# ``PACKAGES_NOT_FOUND`` -# the list of all packages which have not been found -# ``OPTIONAL_PACKAGES_FOUND`` -# only those packages which have been found which have the type OPTIONAL -# ``OPTIONAL_PACKAGES_NOT_FOUND`` -# only those packages which have not been found which have the type OPTIONAL -# ``RECOMMENDED_PACKAGES_FOUND`` -# only those packages which have been found which have the type RECOMMENDED -# ``RECOMMENDED_PACKAGES_NOT_FOUND`` -# only those packages which have not been found which have the type RECOMMENDED -# ``REQUIRED_PACKAGES_FOUND`` -# only those packages which have been found which have the type REQUIRED -# ``REQUIRED_PACKAGES_NOT_FOUND`` -# only those packages which have not been found which have the type REQUIRED -# ``RUNTIME_PACKAGES_FOUND`` -# only those packages which have been found which have the type RUNTIME -# ``RUNTIME_PACKAGES_NOT_FOUND`` -# only those packages which have not been found which have the type RUNTIME -# -# With the exception of the ``ALL`` value, these values can be combined -# in order to customize the output. For example: -# -# :: -# -# feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES) -# -# -# -# If a FILENAME is given, the information is printed into this file. If -# APPEND is used, it is appended to this file, otherwise the file is -# overwritten if it already existed. If the VAR option is used, the -# information is "printed" into the specified variable. If FILENAME is -# not used, the information is printed to the terminal. Using the -# DESCRIPTION option a description or headline can be set which will be -# printed above the actual content. If INCLUDE_QUIET_PACKAGES is given, -# packages which have been searched with find_package(... QUIET) will -# also be listed. By default they are skipped. If -# FATAL_ON_MISSING_REQUIRED_PACKAGES is given, CMake will abort if a -# package which is marked as REQUIRED has not been found. -# -# Example 1, append everything to a file: -# -# :: -# -# feature_summary(WHAT ALL -# FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND) -# -# -# -# Example 2, print the enabled features into the variable -# enabledFeaturesText, including QUIET packages: -# -# :: -# -# feature_summary(WHAT ENABLED_FEATURES -# INCLUDE_QUIET_PACKAGES -# DESCRIPTION "Enabled Features:" -# VAR enabledFeaturesText) -# message(STATUS "${enabledFeaturesText}") -# -# -# -# -# -# :: -# -# SET_PACKAGE_PROPERTIES(<name> PROPERTIES -# [ URL <url> ] -# [ DESCRIPTION <description> ] -# [ TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED) ] -# [ PURPOSE <purpose> ] -# ) -# -# -# -# Use this macro to set up information about the named package, which -# can then be displayed via FEATURE_SUMMARY(). This can be done either -# directly in the Find-module or in the project which uses the module -# after the find_package() call. The features for which information can -# be set are added automatically by the find_package() command. -# -# URL: this should be the homepage of the package, or something similar. -# Ideally this is set already directly in the Find-module. -# -# DESCRIPTION: A short description what that package is, at most one -# sentence. Ideally this is set already directly in the Find-module. -# -# TYPE: What type of dependency has the using project on that package. -# Default is OPTIONAL. In this case it is a package which can be used -# by the project when available at buildtime, but it also work without. -# RECOMMENDED is similar to OPTIONAL, i.e. the project will build if -# the package is not present, but the functionality of the resulting -# binaries will be severly limited. If a REQUIRED package is not -# available at buildtime, the project may not even build. This can be -# combined with the FATAL_ON_MISSING_REQUIRED_PACKAGES argument for -# feature_summary(). Last, a RUNTIME package is a package which is -# actually not used at all during the build, but which is required for -# actually running the resulting binaries. So if such a package is -# missing, the project can still be built, but it may not work later on. -# If set_package_properties() is called multiple times for the same -# package with different TYPEs, the TYPE is only changed to higher TYPEs -# ( RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED ), lower TYPEs are -# ignored. The TYPE property is project-specific, so it cannot be set -# by the Find-module, but must be set in the project. -# -# PURPOSE: This describes which features this package enables in the -# project, i.e. it tells the user what functionality he gets in the -# resulting binaries. If set_package_properties() is called multiple -# times for a package, all PURPOSE properties are appended to a list of -# purposes of the package in the project. As the TYPE property, also -# the PURPOSE property is project-specific, so it cannot be set by the -# Find-module, but must be set in the project. -# -# -# -# Example for setting the info for a package: -# -# :: -# -# find_package(LibXml2) -# set_package_properties(LibXml2 PROPERTIES -# DESCRIPTION "A XML processing library." -# URL "http://xmlsoft.org/") -# -# -# -# :: -# -# set_package_properties(LibXml2 PROPERTIES -# TYPE RECOMMENDED -# PURPOSE "Enables HTML-import in MyWordProcessor") -# ... -# set_package_properties(LibXml2 PROPERTIES -# TYPE OPTIONAL -# PURPOSE "Enables odt-export in MyWordProcessor") -# -# -# -# :: -# -# find_package(DBUS) -# set_package_properties(DBUS PROPERTIES -# TYPE RUNTIME -# PURPOSE "Necessary to disable the screensaver during a presentation" ) -# -# -# -# :: -# -# ADD_FEATURE_INFO(<name> <enabled> <description>) -# -# Use this macro to add information about a feature with the given -# <name>. <enabled> contains whether this feature is enabled or not, -# <description> is a text describing the feature. The information can -# be displayed using feature_summary() for ENABLED_FEATURES and -# DISABLED_FEATURES respectively. -# -# Example for setting the info for a feature: -# -# :: -# -# option(WITH_FOO "Help for foo" ON) -# add_feature_info(Foo WITH_FOO "The Foo feature provides very cool stuff.") -# -# -# -# -# -# The following macros are provided for compatibility with previous -# CMake versions: -# -# :: -# -# SET_PACKAGE_INFO(<name> <description> [<url> [<purpose>] ] ) -# -# Use this macro to set up information about the named package, which -# can then be displayed via FEATURE_SUMMARY(). This can be done either -# directly in the Find-module or in the project which uses the module -# after the find_package() call. The features for which information can -# be set are added automatically by the find_package() command. -# -# :: -# -# PRINT_ENABLED_FEATURES() -# -# Does the same as FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION -# "Enabled features:") -# -# :: -# -# PRINT_DISABLED_FEATURES() -# -# Does the same as FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION -# "Disabled features:") -# -# :: -# -# SET_FEATURE_INFO(<name> <description> [<url>] ) -# -# Does the same as SET_PACKAGE_INFO(<name> <description> <url> ) +#[=======================================================================[.rst: +FeatureSummary +-------------- + +Functions for generating a summary of enabled/disabled features. + +These functions can be used to generate a summary of enabled and disabled +packages and/or feature for a build tree such as:: + + -- The following OPTIONAL packages have been found: + LibXml2 (required version >= 2.4), XML processing lib, <http://xmlsoft.org> + * Enables HTML-import in MyWordProcessor + * Enables odt-export in MyWordProcessor + PNG , A PNG image library. , <http://www.libpng.org/pub/png/> + * Enables saving screenshots + -- The following OPTIONAL packages have not been found: + Lua51 , The Lua scripting language. , <http://www.lua.org> + * Enables macros in MyWordProcessor + Foo , Foo provides cool stuff. + +Functions +^^^^^^^^^ + +#]=======================================================================] #============================================================================= # Copyright 2007-2015 Kitware, Inc. @@ -280,83 +39,6 @@ include("${CMAKE_CURRENT_LIST_DIR}/CMakeParseArguments.cmake") -function(ADD_FEATURE_INFO _name _enabled _desc) - if (${_enabled}) - set_property(GLOBAL APPEND PROPERTY ENABLED_FEATURES "${_name}") - else () - set_property(GLOBAL APPEND PROPERTY DISABLED_FEATURES "${_name}") - endif () - - set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" ) -endfunction() - - - -function(SET_PACKAGE_PROPERTIES _name _props) - if(NOT "${_props}" STREQUAL "PROPERTIES") - message(FATAL_ERROR "PROPERTIES keyword is missing in SET_PACKAGE_PROPERTIES() call.") - endif() - - set(options ) # none - set(oneValueArgs DESCRIPTION URL TYPE PURPOSE ) - set(multiValueArgs ) # none - - CMAKE_PARSE_ARGUMENTS(_SPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if(_SPP_UNPARSED_ARGUMENTS) - message(FATAL_ERROR "Unknown keywords given to SET_PACKAGE_PROPERTIES(): \"${_SPP_UNPARSED_ARGUMENTS}\"") - endif() - - if(_SPP_DESCRIPTION) - get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION) - if(_info AND NOT "${_info}" STREQUAL "${_SPP_DESCRIPTION}") - message(STATUS "Warning: Property DESCRIPTION for package ${_name} already set to \"${_info}\", overriding it with \"${_SPP_DESCRIPTION}\"") - endif() - - set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_SPP_DESCRIPTION}" ) - endif() - - - if(_SPP_URL) - get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_URL) - if(_info AND NOT "${_info}" STREQUAL "${_SPP_URL}") - message(STATUS "Warning: Property URL already set to \"${_info}\", overriding it with \"${_SPP_URL}\"") - endif() - - set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_SPP_URL}" ) - endif() - - - # handle the PURPOSE: use APPEND, since there can be multiple purposes for one package inside a project - if(_SPP_PURPOSE) - set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_SPP_PURPOSE}" ) - endif() - - # handle the TYPE - if(NOT _SPP_TYPE) - set(_SPP_TYPE OPTIONAL) - endif() - - # List the supported types, according to their priority - set(validTypes "RUNTIME" "OPTIONAL" "RECOMMENDED" "REQUIRED" ) - list(FIND validTypes ${_SPP_TYPE} _typeIndexInList) - if("${_typeIndexInList}" STREQUAL "-1" ) - message(FATAL_ERROR "Bad package property type ${_SPP_TYPE} used in SET_PACKAGE_PROPERTIES(). " - "Valid types are OPTIONAL, RECOMMENDED, REQUIRED and RUNTIME." ) - endif() - - get_property(_previousType GLOBAL PROPERTY _CMAKE_${_name}_TYPE) - list(FIND validTypes "${_previousType}" _prevTypeIndexInList) - - # make sure a previously set TYPE is not overridden with a lower new TYPE: - if("${_typeIndexInList}" GREATER "${_prevTypeIndexInList}") - set_property(GLOBAL PROPERTY _CMAKE_${_name}_TYPE "${_SPP_TYPE}" ) - endif() - -endfunction() - - - function(_FS_GET_FEATURE_SUMMARY _property _var _includeQuiet) set(_type "ANY") @@ -439,6 +121,97 @@ function(_FS_GET_FEATURE_SUMMARY _property _var _includeQuiet) endfunction() +#[=======================================================================[.rst: +.. command:: feature_summary + + :: + + feature_summary( [FILENAME <file>] + [APPEND] + [VAR <variable_name>] + [INCLUDE_QUIET_PACKAGES] + [FATAL_ON_MISSING_REQUIRED_PACKAGES] + [DESCRIPTION "Found packages:"] + WHAT (ALL | PACKAGES_FOUND | PACKAGES_NOT_FOUND + | ENABLED_FEATURES | DISABLED_FEATURES) + ) + + The ``feature_summary()`` macro can be used to print information about + enabled or disabled packages or features of a project. By default, + only the names of the features/packages will be printed and their + required version when one was specified. Use ``set_package_properties()`` + to add more useful information, like e.g. a download URL for the + respective package or their purpose in the project. + + The ``WHAT`` option is the only mandatory option. Here you specify what + information will be printed: + + ``ALL`` + print everything + ``ENABLED_FEATURES`` + the list of all features which are enabled + ``DISABLED_FEATURES`` + the list of all features which are disabled + ``PACKAGES_FOUND`` + the list of all packages which have been found + ``PACKAGES_NOT_FOUND`` + the list of all packages which have not been found + ``OPTIONAL_PACKAGES_FOUND`` + only those packages which have been found which have the type OPTIONAL + ``OPTIONAL_PACKAGES_NOT_FOUND`` + only those packages which have not been found which have the type OPTIONAL + ``RECOMMENDED_PACKAGES_FOUND`` + only those packages which have been found which have the type RECOMMENDED + ``RECOMMENDED_PACKAGES_NOT_FOUND`` + only those packages which have not been found which have the type RECOMMENDED + ``REQUIRED_PACKAGES_FOUND`` + only those packages which have been found which have the type REQUIRED + ``REQUIRED_PACKAGES_NOT_FOUND`` + only those packages which have not been found which have the type REQUIRED + ``RUNTIME_PACKAGES_FOUND`` + only those packages which have been found which have the type RUNTIME + ``RUNTIME_PACKAGES_NOT_FOUND`` + only those packages which have not been found which have the type RUNTIME + + With the exception of the ``ALL`` value, these values can be combined + in order to customize the output. For example: + + .. code-block:: cmake + + feature_summary(WHAT ENABLED_FEATURES DISABLED_FEATURES) + + If a ``FILENAME`` is given, the information is printed into this file. If + ``APPEND`` is used, it is appended to this file, otherwise the file is + overwritten if it already existed. If the VAR option is used, the + information is "printed" into the specified variable. If ``FILENAME`` is + not used, the information is printed to the terminal. Using the + ``DESCRIPTION`` option a description or headline can be set which will be + printed above the actual content. If ``INCLUDE_QUIET_PACKAGES`` is given, + packages which have been searched with ``find_package(... QUIET)`` will + also be listed. By default they are skipped. If + ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` is given, CMake will abort if a + package which is marked as ``REQUIRED`` has not been found. + + Example 1, append everything to a file: + + .. code-block:: cmake + + include(FeatureSummary) + feature_summary(WHAT ALL + FILENAME ${CMAKE_BINARY_DIR}/all.log APPEND) + + Example 2, print the enabled features into the variable + enabledFeaturesText, including QUIET packages: + + .. code-block:: cmake + + include(FeatureSummary) + feature_summary(WHAT ENABLED_FEATURES + INCLUDE_QUIET_PACKAGES + DESCRIPTION "Enabled Features:" + VAR enabledFeaturesText) + message(STATUS "${enabledFeaturesText}") +#]=======================================================================] function(FEATURE_SUMMARY) # CMAKE_PARSE_ARGUMENTS(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...) @@ -558,9 +331,198 @@ function(FEATURE_SUMMARY) endfunction() +#[=======================================================================[.rst: +.. command:: set_package_properties + + :: + + set_package_properties(<name> PROPERTIES + [ URL <url> ] + [ DESCRIPTION <description> ] + [ TYPE (RUNTIME|OPTIONAL|RECOMMENDED|REQUIRED) ] + [ PURPOSE <purpose> ] + ) + + Use this macro to set up information about the named package, which + can then be displayed via FEATURE_SUMMARY(). This can be done either + directly in the Find-module or in the project which uses the module + after the find_package() call. The features for which information can + be set are added automatically by the find_package() command. + + ``URL <url>`` + This should be the homepage of the package, or something similar. + Ideally this is set already directly in the Find-module. + + ``DESCRIPTION <description>`` + A short description what that package is, at most one sentence. + Ideally this is set already directly in the Find-module. + + ``TYPE <type>`` + What type of dependency has the using project on that package. + Default is ``OPTIONAL``. In this case it is a package which can be used + by the project when available at buildtime, but it also work without. + ``RECOMMENDED`` is similar to ``OPTIONAL``, i.e. the project will build if + the package is not present, but the functionality of the resulting + binaries will be severly limited. If a ``REQUIRED`` package is not + available at buildtime, the project may not even build. This can be + combined with the ``FATAL_ON_MISSING_REQUIRED_PACKAGES`` argument for + ``feature_summary()``. Last, a ``RUNTIME`` package is a package which is + actually not used at all during the build, but which is required for + actually running the resulting binaries. So if such a package is + missing, the project can still be built, but it may not work later on. + If ``set_package_properties()`` is called multiple times for the same + package with different TYPEs, the ``TYPE`` is only changed to higher + TYPEs (``RUNTIME < OPTIONAL < RECOMMENDED < REQUIRED``), lower TYPEs are + ignored. The ``TYPE`` property is project-specific, so it cannot be set + by the Find-module, but must be set in the project. + + + ``PURPOSE <purpose>`` + This describes which features this package enables in the + project, i.e. it tells the user what functionality he gets in the + resulting binaries. If set_package_properties() is called multiple + times for a package, all PURPOSE properties are appended to a list of + purposes of the package in the project. As the TYPE property, also + the PURPOSE property is project-specific, so it cannot be set by the + Find-module, but must be set in the project. + + Example for setting the info for a package: + + .. code-block:: cmake + + find_package(LibXml2) + set_package_properties(LibXml2 PROPERTIES + DESCRIPTION "A XML processing library." + URL "http://xmlsoft.org/") + # or + set_package_properties(LibXml2 PROPERTIES + TYPE RECOMMENDED + PURPOSE "Enables HTML-import in MyWordProcessor") + # or + set_package_properties(LibXml2 PROPERTIES + TYPE OPTIONAL + PURPOSE "Enables odt-export in MyWordProcessor") + + find_package(DBUS) + set_package_properties(DBUS PROPERTIES + TYPE RUNTIME + PURPOSE "Necessary to disable the screensaver during a presentation") +#]=======================================================================] +function(SET_PACKAGE_PROPERTIES _name _props) + if(NOT "${_props}" STREQUAL "PROPERTIES") + message(FATAL_ERROR "PROPERTIES keyword is missing in SET_PACKAGE_PROPERTIES() call.") + endif() + + set(options ) # none + set(oneValueArgs DESCRIPTION URL TYPE PURPOSE ) + set(multiValueArgs ) # none + + CMAKE_PARSE_ARGUMENTS(_SPP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(_SPP_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to SET_PACKAGE_PROPERTIES(): \"${_SPP_UNPARSED_ARGUMENTS}\"") + endif() + + if(_SPP_DESCRIPTION) + get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION) + if(_info AND NOT "${_info}" STREQUAL "${_SPP_DESCRIPTION}") + message(STATUS "Warning: Property DESCRIPTION for package ${_name} already set to \"${_info}\", overriding it with \"${_SPP_DESCRIPTION}\"") + endif() + + set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_SPP_DESCRIPTION}" ) + endif() + + + if(_SPP_URL) + get_property(_info GLOBAL PROPERTY _CMAKE_${_name}_URL) + if(_info AND NOT "${_info}" STREQUAL "${_SPP_URL}") + message(STATUS "Warning: Property URL already set to \"${_info}\", overriding it with \"${_SPP_URL}\"") + endif() + + set_property(GLOBAL PROPERTY _CMAKE_${_name}_URL "${_SPP_URL}" ) + endif() + + + # handle the PURPOSE: use APPEND, since there can be multiple purposes for one package inside a project + if(_SPP_PURPOSE) + set_property(GLOBAL APPEND PROPERTY _CMAKE_${_name}_PURPOSE "${_SPP_PURPOSE}" ) + endif() + + # handle the TYPE + if(NOT _SPP_TYPE) + set(_SPP_TYPE OPTIONAL) + endif() + + # List the supported types, according to their priority + set(validTypes "RUNTIME" "OPTIONAL" "RECOMMENDED" "REQUIRED" ) + list(FIND validTypes ${_SPP_TYPE} _typeIndexInList) + if("${_typeIndexInList}" STREQUAL "-1" ) + message(FATAL_ERROR "Bad package property type ${_SPP_TYPE} used in SET_PACKAGE_PROPERTIES(). " + "Valid types are OPTIONAL, RECOMMENDED, REQUIRED and RUNTIME." ) + endif() + + get_property(_previousType GLOBAL PROPERTY _CMAKE_${_name}_TYPE) + list(FIND validTypes "${_previousType}" _prevTypeIndexInList) + + # make sure a previously set TYPE is not overridden with a lower new TYPE: + if("${_typeIndexInList}" GREATER "${_prevTypeIndexInList}") + set_property(GLOBAL PROPERTY _CMAKE_${_name}_TYPE "${_SPP_TYPE}" ) + endif() + +endfunction() + +#[=======================================================================[.rst: +.. command:: add_feature_info + + :: + + add_feature_info(<name> <enabled> <description>) + + Use this macro to add information about a feature with the given ``<name>``. + ``<enabled>`` contains whether this feature is enabled or not. + ``<description>`` is a text describing the feature. The information can + be displayed using ``feature_summary()`` for ``ENABLED_FEATURES`` and + ``DISABLED_FEATURES`` respectively. + + Example for setting the info for a feature: + + .. code-block:: cmake + + option(WITH_FOO "Help for foo" ON) + add_feature_info(Foo WITH_FOO "The Foo feature provides very cool stuff.") +#]=======================================================================] +function(ADD_FEATURE_INFO _name _enabled _desc) + if (${_enabled}) + set_property(GLOBAL APPEND PROPERTY ENABLED_FEATURES "${_name}") + else () + set_property(GLOBAL APPEND PROPERTY DISABLED_FEATURES "${_name}") + endif () + + set_property(GLOBAL PROPERTY _CMAKE_${_name}_DESCRIPTION "${_desc}" ) +endfunction() + # The stuff below is only kept for compatibility +#[=======================================================================[.rst: +Legacy Macros +^^^^^^^^^^^^^ + +The following macros are provided for compatibility with previous +CMake versions: + +.. command:: set_package_info + + :: + + set_package_info(<name> <description> [ <url> [<purpose>] ]) + + Use this macro to set up information about the named package, which + can then be displayed via ``feature_summary()``. This can be done either + directly in the Find-module or in the project which uses the module + after the :command:`find_package` call. The features for which information + can be set are added automatically by the ``find_package()`` command. +#]=======================================================================] function(SET_PACKAGE_INFO _name _desc) unset(_url) unset(_purpose) @@ -579,20 +541,51 @@ function(SET_PACKAGE_INFO _name _desc) endif() endfunction() +#[=======================================================================[.rst: +.. command:: set_feature_info + :: + set_feature_info(<name> <description> [<url>]) + + Does the same as:: + + set_package_info(<name> <description> <url>) +#]=======================================================================] function(SET_FEATURE_INFO) SET_PACKAGE_INFO(${ARGN}) endfunction() +#[=======================================================================[.rst: +.. command:: print_enabled_features + + :: + + print_enabled_features() + Does the same as + .. code-block:: cmake + + feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:") +#]=======================================================================] function(PRINT_ENABLED_FEATURES) FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:") endfunction() +#[=======================================================================[.rst: +.. command:: print_disabled_features + + :: + + print_disabled_features() + + Does the same as + .. code-block:: cmake + feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:") +#]=======================================================================] function(PRINT_DISABLED_FEATURES) FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:") endfunction() diff --git a/Modules/FindCUDA.cmake b/Modules/FindCUDA.cmake index aaa1536..6b76c25 100644 --- a/Modules/FindCUDA.cmake +++ b/Modules/FindCUDA.cmake @@ -303,6 +303,8 @@ # CUDA_ADD_CUBLAS_TO_TARGET macro). # CUDA_cudart_static_LIBRARY -- Statically linkable cuda runtime library. # Only available for CUDA version 5.5+ +# CUDA_cudadevrt_LIBRARY -- Device runtime library. +# Required for separable compilation. # CUDA_cupti_LIBRARY -- CUDA Profiling Tools Interface library. # Only available for CUDA version 4.0+. # CUDA_curand_LIBRARY -- CUDA Random Number Generation library. @@ -564,6 +566,7 @@ macro(cuda_unset_include_and_libraries) unset(CUDA_CUDARTEMU_LIBRARY CACHE) endif() unset(CUDA_cudart_static_LIBRARY CACHE) + unset(CUDA_cudadevrt_LIBRARY CACHE) unset(CUDA_cublas_LIBRARY CACHE) unset(CUDA_cublas_device_LIBRARY CACHE) unset(CUDA_cublasemu_LIBRARY CACHE) @@ -794,6 +797,10 @@ else() set(CUDA_USE_STATIC_CUDA_RUNTIME OFF CACHE INTERNAL "") set(CUDA_CUDART_LIBRARY_VAR CUDA_CUDART_LIBRARY) endif() +if(NOT CUDA_VERSION VERSION_LESS "5.0") + cuda_find_library_local_first(CUDA_cudadevrt_LIBRARY cudadevrt "\"cudadevrt\" library") + mark_as_advanced(CUDA_cudadevrt_LIBRARY) +endif() if(CUDA_USE_STATIC_CUDA_RUNTIME) if(UNIX) @@ -1737,6 +1744,12 @@ macro(CUDA_ADD_LIBRARY cuda_target) ${CUDA_LIBRARIES} ) + if(CUDA_SEPARABLE_COMPILATION) + target_link_libraries(${cuda_target} + ${CUDA_cudadevrt_LIBRARY} + ) + endif() + # We need to set the linker language based on what the expected generated file # would be. CUDA_C_OR_CXX is computed based on CUDA_HOST_COMPILATION_CPP. set_target_properties(${cuda_target} diff --git a/Modules/FindMatlab.cmake b/Modules/FindMatlab.cmake index b501599..c813f8f 100644 --- a/Modules/FindMatlab.cmake +++ b/Modules/FindMatlab.cmake @@ -635,7 +635,7 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve set(devnull INPUT_FILE NUL) endif() - # timeout set to 30 seconds, in case it does not start + # timeout set to 120 seconds, in case it does not start # note as said before OUTPUT_VARIABLE cannot be used in a platform # independent manner however, not setting it would flush the output of Matlab # in the current console (unix variant) @@ -644,11 +644,18 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve OUTPUT_VARIABLE _matlab_version_from_cmd_dummy RESULT_VARIABLE _matlab_result_version_call ERROR_VARIABLE _matlab_result_version_call_error - TIMEOUT 30 + TIMEOUT 120 WORKING_DIRECTORY "${_matlab_temporary_folder}" ${devnull} ) + if("${_matlab_result_version_call}" MATCHES "timeout") + if(MATLAB_FIND_DEBUG) + message(WARNING "[MATLAB] Unable to determine the version of Matlab." + " Matlab call timed out after 120 seconds.") + endif() + return() + endif() if(${_matlab_result_version_call}) if(MATLAB_FIND_DEBUG) @@ -698,7 +705,6 @@ function(matlab_get_version_from_matlab_run matlab_binary_program matlab_list_ve endfunction() - #.rst: # .. command:: matlab_add_unit_test # @@ -720,6 +726,7 @@ endfunction() # matlab_add_unit_test( # NAME <name> # UNITTEST_FILE matlab_file_containing_unittest.m +# [CUSTOM_MATLAB_COMMAND matlab_command_to_run_as_test] # [UNITTEST_PRECOMMAND matlab_command_to_run] # [TIMEOUT timeout] # [ADDITIONAL_PATH path1 [path2 ...]] @@ -735,6 +742,11 @@ endfunction() # ``UNITTEST_FILE`` # the matlab unittest file. Its path will be automatically # added to the Matlab path. +# ``CUSTOM_MATLAB_COMMAND`` +# Matlab script command to run as the test. +# IIf this is not set, then the following is run: +# "runtests('matlab_file_name'), exit(max([ans(1,:).Failed])) +# matlab_file_name comes from UNITTEST_FILE without the .m. # ``UNITTEST_PRECOMMAND`` # Matlab script command to be ran before the file # containing the test (eg. GPU device initialisation based on CMake @@ -748,12 +760,18 @@ endfunction() # ``MATLAB_ADDITIONAL_STARTUP_OPTIONS`` # a list of additional option in order # to run Matlab from the command line. +# -nosplash -nodesktop -nodisplay are always added. # ``TEST_ARGS`` # Additional options provided to the add_test command. These # options are added to the default options (eg. "CONFIGURATIONS Release") # ``NO_UNITTEST_FRAMEWORK`` # when set, indicates that the test should not # use the unittest framework of Matlab (available for versions >= R2013a). +# ``WORKING_DIRECTORY`` +# This will be the working directory for the test. If specified it will +# also be the output directory used for the log file of the test run. +# If not specifed the temporary directory ${CMAKE_BINARY_DIR}/Matlab will +# be used as the working directory and the log location. # function(matlab_add_unit_test) @@ -762,11 +780,12 @@ function(matlab_add_unit_test) endif() set(options NO_UNITTEST_FRAMEWORK) - set(oneValueArgs NAME UNITTEST_PRECOMMAND UNITTEST_FILE TIMEOUT) + set(oneValueArgs NAME UNITTEST_FILE TIMEOUT WORKING_DIRECTORY + UNITTEST_PRECOMMAND CUSTOM_TEST_COMMAND) set(multiValueArgs ADDITIONAL_PATH MATLAB_ADDITIONAL_STARTUP_OPTIONS TEST_ARGS) set(prefix _matlab_unittest_prefix) - cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + cmake_parse_arguments(PARSE_ARGV 0 ${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ) if(NOT ${prefix}_NAME) message(FATAL_ERROR "[MATLAB] The Matlab test name cannot be empty") @@ -774,15 +793,17 @@ function(matlab_add_unit_test) add_test(NAME ${${prefix}_NAME} COMMAND ${CMAKE_COMMAND} - -Dtest_name=${${prefix}_NAME} - -Dadditional_paths=${${prefix}_ADDITIONAL_PATH} - -Dtest_timeout=${${prefix}_TIMEOUT} - -Doutput_directory=${_matlab_temporary_folder} - -DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM} - -Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK} - -DMatlab_ADDITIONNAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS} - -Dunittest_file_to_run=${${prefix}_UNITTEST_FILE} - -Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND} + "-Dtest_name=${${prefix}_NAME}" + "-Dadditional_paths=${${prefix}_ADDITIONAL_PATH}" + "-Dtest_timeout=${${prefix}_TIMEOUT}" + "-Doutput_directory=${_matlab_temporary_folder}" + "-Dworking_directory=${${prefix}_WORKING_DIRECTORY}" + "-DMatlab_PROGRAM=${Matlab_MAIN_PROGRAM}" + "-Dno_unittest_framework=${${prefix}_NO_UNITTEST_FRAMEWORK}" + "-DMatlab_ADDITIONNAL_STARTUP_OPTIONS=${${prefix}_MATLAB_ADDITIONAL_STARTUP_OPTIONS}" + "-Dunittest_file_to_run=${${prefix}_UNITTEST_FILE}" + "-Dcustom_Matlab_test_command=${${prefix}_CUSTOM_TEST_COMMAND}" + "-Dcmd_to_run_before_test=${${prefix}_UNITTEST_PRECOMMAND}" -P ${_FindMatlab_SELF_DIR}/MatlabTestsRedirect.cmake ${${prefix}_TEST_ARGS} ${${prefix}_UNPARSED_ARGUMENTS} @@ -1034,7 +1055,7 @@ function(_Matlab_get_version_from_root matlab_root matlab_known_version matlab_f if(${list_of_all_versions_length} GREATER 0) list(GET matlab_list_of_all_versions 0 _matlab_version_tmp) else() - set(_matlab_version_tmp "") + set(_matlab_version_tmp "unknown") endif() # set the version into the cache diff --git a/Modules/FindPostgreSQL.cmake b/Modules/FindPostgreSQL.cmake index 32a3f0a..84fa541 100644 --- a/Modules/FindPostgreSQL.cmake +++ b/Modules/FindPostgreSQL.cmake @@ -37,7 +37,7 @@ # In Windows the default installation of PostgreSQL uses that as part of the path. # E.g C:\Program Files\PostgreSQL\8.4. # Currently, the following version numbers are known to this module: -# "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" +# "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0" # # To use this variable just do something like this: # set(PostgreSQL_ADDITIONAL_VERSIONS "9.2" "8.4.4") @@ -81,7 +81,7 @@ set(PostgreSQL_ROOT_DIR_MESSAGE "Set the PostgreSQL_ROOT system variable to wher set(PostgreSQL_KNOWN_VERSIONS ${PostgreSQL_ADDITIONAL_VERSIONS} - "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") + "9.6" "9.5" "9.4" "9.3" "9.2" "9.1" "9.0" "8.4" "8.3" "8.2" "8.1" "8.0") # Define additional search paths for root directories. set( PostgreSQL_ROOT_DIRECTORIES diff --git a/Modules/FindPythonInterp.cmake b/Modules/FindPythonInterp.cmake index e194185..4d726f2 100644 --- a/Modules/FindPythonInterp.cmake +++ b/Modules/FindPythonInterp.cmake @@ -52,7 +52,7 @@ unset(_Python_NAMES) set(_PYTHON1_VERSIONS 1.6 1.5) set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) -set(_PYTHON3_VERSIONS 3.6 3.5 3.4 3.3 3.2 3.1 3.0) +set(_PYTHON3_VERSIONS 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) if(PythonInterp_FIND_VERSION) if(PythonInterp_FIND_VERSION_COUNT GREATER 1) diff --git a/Modules/FindPythonLibs.cmake b/Modules/FindPythonLibs.cmake index ab92f86..d9916a1 100644 --- a/Modules/FindPythonLibs.cmake +++ b/Modules/FindPythonLibs.cmake @@ -84,7 +84,7 @@ set(CMAKE_FIND_FRAMEWORK LAST) set(_PYTHON1_VERSIONS 1.6 1.5) set(_PYTHON2_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) -set(_PYTHON3_VERSIONS 3.6 3.5 3.4 3.3 3.2 3.1 3.0) +set(_PYTHON3_VERSIONS 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) if(PythonLibs_FIND_VERSION) if(PythonLibs_FIND_VERSION_COUNT GREATER 1) diff --git a/Modules/GenerateExportHeader.cmake b/Modules/GenerateExportHeader.cmake index e33b927..bacf137 100644 --- a/Modules/GenerateExportHeader.cmake +++ b/Modules/GenerateExportHeader.cmake @@ -208,7 +208,7 @@ macro(_test_compiler_hidden_visibility) if(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.2") set(GCC_TOO_OLD TRUE) - elseif(CMAKE_COMPILER_IS_GNUC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2") + elseif(CMAKE_COMPILER_IS_GNUCC AND CMAKE_C_COMPILER_VERSION VERSION_LESS "4.2") set(GCC_TOO_OLD TRUE) elseif(CMAKE_CXX_COMPILER_ID MATCHES Intel AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0") set(_INTEL_TOO_OLD TRUE) diff --git a/Modules/MatlabTestsRedirect.cmake b/Modules/MatlabTestsRedirect.cmake index 0ef4c3e..76f9a53 100644 --- a/Modules/MatlabTestsRedirect.cmake +++ b/Modules/MatlabTestsRedirect.cmake @@ -23,11 +23,12 @@ # -DMatlab_PROGRAM=matlab_exe_location # -DMatlab_ADDITIONNAL_STARTUP_OPTIONS="" # -Dtest_name=name_of_the_test +# -Dcustom_Matlab_test_command="" # -Dcmd_to_run_before_test="" # -Dunittest_file_to_run # -P FindMatlab_TestsRedirect.cmake -set(Matlab_UNIT_TESTS_CMD -nosplash -nojvm -nodesktop -nodisplay ${Matlab_ADDITIONNAL_STARTUP_OPTIONS}) +set(Matlab_UNIT_TESTS_CMD -nosplash -nodesktop -nodisplay ${Matlab_ADDITIONNAL_STARTUP_OPTIONS}) if(WIN32) set(Matlab_UNIT_TESTS_CMD ${Matlab_UNIT_TESTS_CMD} -wait) endif() @@ -36,6 +37,13 @@ if(NOT test_timeout) set(test_timeout 180) endif() +# If timeout is -1, then do not put a timeout on the execute_process +if(test_timeout EQUAL -1) + set(test_timeout "") +else() + set(test_timeout TIMEOUT ${test_timeout}) +endif() + if(NOT cmd_to_run_before_test) set(cmd_to_run_before_test) endif() @@ -50,16 +58,30 @@ foreach(s IN LISTS additional_paths) endif() endforeach() -set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))") +if(custom_Matlab_test_command) + set(unittest_to_run "${custom_Matlab_test_command}") +else() + set(unittest_to_run "runtests('${unittest_file_to_run_name}'), exit(max([ans(1,:).Failed]))") +endif() + + if(no_unittest_framework) set(unittest_to_run "try, ${unittest_file_to_run_name}, catch err, disp('An exception has been thrown during the execution'), disp(err), disp(err.stack), exit(1), end, exit(0)") endif() set(Matlab_SCRIPT_TO_RUN - "addpath(${concat_string}), path, ${cmd_to_run_before_test}, ${unittest_to_run}" + "addpath(${concat_string}); ${cmd_to_run_before_test}; ${unittest_to_run}" ) +# if the working directory is not specified then default +# to the output_directory because the log file will go there +# if the working_directory is specified it will override the +# output_directory +if(NOT working_directory) + set(working_directory "${output_directory}") +endif() -set(Matlab_LOG_FILE "${output_directory}/${test_name}.log") +string(REPLACE "/" "_" log_file_name "${test_name}.log") +set(Matlab_LOG_FILE "${working_directory}/${log_file_name}") set(devnull) if(UNIX) @@ -69,11 +91,14 @@ elseif(WIN32) endif() execute_process( - COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${test_name}.log" -r "${Matlab_SCRIPT_TO_RUN}" + # Do not use a full path to log file. Depend on the fact that the log file + # is always going to go in the working_directory. This is because matlab + # on unix is a shell script that does not handle spaces in the logfile path. + COMMAND "${Matlab_PROGRAM}" ${Matlab_UNIT_TESTS_CMD} -logfile "${log_file_name}" -r "${Matlab_SCRIPT_TO_RUN}" RESULT_VARIABLE res - TIMEOUT ${test_timeout} + ${test_timeout} OUTPUT_QUIET # we do not want the output twice - WORKING_DIRECTORY "${output_directory}" + WORKING_DIRECTORY "${working_directory}" ${devnull} ) @@ -87,5 +112,5 @@ message("Matlab test ${name_of_the_test} output:\n${matlab_log_content}") # if w if(NOT (res EQUAL 0)) - message( FATAL_ERROR "[MATLAB] TEST FAILED" ) + message( FATAL_ERROR "[MATLAB] TEST FAILED Matlab returned ${res}" ) endif() diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index f5c2e52..a2dead6 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -221,10 +221,14 @@ set(SRCS cmExprLexer.cxx cmExprParser.cxx cmExprParserHelper.cxx + cmExportBuildAndroidMKGenerator.h + cmExportBuildAndroidMKGenerator.cxx cmExportBuildFileGenerator.h cmExportBuildFileGenerator.cxx cmExportFileGenerator.h cmExportFileGenerator.cxx + cmExportInstallAndroidMKGenerator.h + cmExportInstallAndroidMKGenerator.cxx cmExportInstallFileGenerator.h cmExportInstallFileGenerator.cxx cmExportTryCompileFileGenerator.h @@ -782,6 +786,17 @@ add_executable(cmake cmakemain.cxx cmcmd.cxx cmcmd.h ${MANIFEST_FILE}) list(APPEND _tools cmake) target_link_libraries(cmake CMakeLib) +if(CMake_HAVE_SERVER_MODE) + add_library(CMakeServerLib + cmServer.cxx cmServer.h + cmServerProtocol.cxx cmServerProtocol.h + ) + target_link_libraries(CMakeServerLib CMakeLib) + set_property(SOURCE cmcmd.cxx APPEND PROPERTY COMPILE_DEFINITIONS HAVE_SERVER_MODE=1) + + target_link_libraries(cmake CMakeServerLib) +endif() + # Build CTest executable add_executable(ctest ctest.cxx ${MANIFEST_FILE}) list(APPEND _tools ctest) diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index e77c982..d725626 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,5 +1,5 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 6) -set(CMake_VERSION_PATCH 20160912) +set(CMake_VERSION_PATCH 20160921) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/IFW/cmCPackIFWGenerator.cxx b/Source/CPack/IFW/cmCPackIFWGenerator.cxx index a6f1585..fa7e0aa 100644 --- a/Source/CPack/IFW/cmCPackIFWGenerator.cxx +++ b/Source/CPack/IFW/cmCPackIFWGenerator.cxx @@ -130,6 +130,19 @@ int cmCPackIFWGenerator::PackageFiles() { std::string ifwCmd = BinCreator; ifwCmd += " -c " + this->toplevel + "/config/config.xml"; + + if (!Installer.Resources.empty()) { + ifwCmd += " -r "; + std::vector<std::string>::iterator it = Installer.Resources.begin(); + std::string path = this->toplevel + "/resources/"; + ifwCmd += path + *it; + ++it; + while (it != Installer.Resources.end()) { + ifwCmd += "," + path + *it; + ++it; + } + } + ifwCmd += " -p " + this->toplevel + "/packages"; if (!PkgsDirsVector.empty()) { diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.cxx b/Source/CPack/IFW/cmCPackIFWInstaller.cxx index 5a3efc9..aa609e2 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.cxx +++ b/Source/CPack/IFW/cmCPackIFWInstaller.cxx @@ -13,11 +13,13 @@ #include "cmCPackIFWInstaller.h" #include "CPack/cmCPackGenerator.h" +#include "CPack/cmCPackLog.h" #include "cmCPackIFWGenerator.h" #include "cmCPackIFWPackage.h" #include "cmCPackIFWRepository.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" +#include "cmXMLParser.h" #include "cmXMLWriter.h" #include <cmConfigure.h> @@ -198,8 +200,70 @@ void cmCPackIFWInstaller::ConfigureFromOptions() this->GetOption("CPACK_IFW_PACKAGE_CONTROL_SCRIPT")) { ControlScript = optIFW_CONTROL_SCRIPT; } + + // Resources + if (const char* optIFW_PACKAGE_RESOURCES = + this->GetOption("CPACK_IFW_PACKAGE_RESOURCES")) { + Resources.clear(); + cmSystemTools::ExpandListArgument(optIFW_PACKAGE_RESOURCES, Resources); + } } +/** \class cmCPackIFWResourcesParser + * \brief Helper class that parse resources form .qrc (Qt) + */ +class cmCPackIFWResourcesParser : public cmXMLParser +{ +public: + cmCPackIFWResourcesParser(cmCPackIFWInstaller* i) + : installer(i) + , file(false) + { + path = i->Directory + "/resources"; + } + + bool ParseResource(size_t r) + { + hasFiles = false; + hasErrors = false; + + basePath = cmSystemTools::GetFilenamePath(installer->Resources[r].data()); + + ParseFile(installer->Resources[r].data()); + + return hasFiles && !hasErrors; + } + + cmCPackIFWInstaller* installer; + bool file, hasFiles, hasErrors; + std::string path, basePath; + +protected: + void StartElement(const std::string& name, const char** /*atts*/) CM_OVERRIDE + { + file = name == "file" ? true : false; + if (file) { + hasFiles = true; + } + } + + void CharacterDataHandler(const char* data, int length) CM_OVERRIDE + { + if (file) { + std::string content(data, data + length); + content = cmSystemTools::TrimWhitespace(content); + std::string source = basePath + "/" + content; + std::string destination = path + "/" + content; + if (!cmSystemTools::CopyFileIfDifferent(source.data(), + destination.data())) { + hasErrors = true; + } + } + } + + void EndElement(const std::string& /*name*/) CM_OVERRIDE {} +}; + void cmCPackIFWInstaller::GenerateInstallerFile() { // Lazy directory initialization @@ -315,6 +379,26 @@ void cmCPackIFWInstaller::GenerateInstallerFile() xout.Element("ControlScript", name); } + // Resources (copy to resources dir) + if (!Resources.empty()) { + std::vector<std::string> resources; + cmCPackIFWResourcesParser parser(this); + for (size_t i = 0; i < Resources.size(); i++) { + if (parser.ParseResource(i)) { + std::string name = cmSystemTools::GetFilenameName(Resources[i]); + std::string path = Directory + "/resources/" + name; + cmsys::SystemTools::CopyFileIfDifferent(Resources[i].data(), + path.data()); + resources.push_back(name); + } else { + cmCPackLogger(cmCPackLog::LOG_WARNING, "Can't copy resources from \"" + << Resources[i] << "\". Resource will be skipped." + << std::endl); + } + } + Resources = resources; + } + xout.EndElement(); xout.EndDocument(); } diff --git a/Source/CPack/IFW/cmCPackIFWInstaller.h b/Source/CPack/IFW/cmCPackIFWInstaller.h index f72d379..c9265ec 100644 --- a/Source/CPack/IFW/cmCPackIFWInstaller.h +++ b/Source/CPack/IFW/cmCPackIFWInstaller.h @@ -94,6 +94,9 @@ public: /// Filename for a custom installer control script std::string ControlScript; + /// List of resources to include in the installer binary + std::vector<std::string> Resources; + public: // Internal implementation diff --git a/Source/CPack/IFW/cmCPackIFWPackage.cxx b/Source/CPack/IFW/cmCPackIFWPackage.cxx index bc503fc..2d3cf12 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.cxx +++ b/Source/CPack/IFW/cmCPackIFWPackage.cxx @@ -153,6 +153,7 @@ void cmCPackIFWPackage::DefaultConfiguration() ReleaseDate = ""; Script = ""; Licenses.clear(); + UserInterfaces.clear(); SortingPriority = ""; Default = ""; Essential = ""; @@ -229,6 +230,12 @@ int cmCPackIFWPackage::ConfigureFromComponent(cmCPackComponent* component) Script = option; } + // User interfaces + if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) { + UserInterfaces.clear(); + cmSystemTools::ExpandListArgument(option, UserInterfaces); + } + // CMake dependencies if (!component->Dependencies.empty()) { std::vector<cmCPackComponent*>::iterator dit; @@ -322,6 +329,12 @@ int cmCPackIFWPackage::ConfigureFromGroup(cmCPackComponentGroup* group) Script = option; } + // User interfaces + if (const char* option = this->GetOption(prefix + "USER_INTERFACES")) { + UserInterfaces.clear(); + cmSystemTools::ExpandListArgument(option, UserInterfaces); + } + // Licenses if (const char* option = this->GetOption(prefix + "LICENSES")) { Licenses.clear(); @@ -417,6 +430,23 @@ void cmCPackIFWPackage::GeneratePackageFile() xout.Element("Script", name); } + // User Interfaces (copy to meta dir) + std::vector<std::string> userInterfaces = UserInterfaces; + for (size_t i = 0; i < userInterfaces.size(); i++) { + std::string name = cmSystemTools::GetFilenameName(userInterfaces[i]); + std::string path = Directory + "/meta/" + name; + cmsys::SystemTools::CopyFileIfDifferent(userInterfaces[i].data(), + path.data()); + userInterfaces[i] = name; + } + if (!userInterfaces.empty()) { + xout.StartElement("UserInterfaces"); + for (size_t i = 0; i < userInterfaces.size(); i++) { + xout.Element("UserInterface", userInterfaces[i]); + } + xout.EndElement(); + } + // Dependencies std::set<DependenceStruct> compDepSet; for (std::set<DependenceStruct*>::iterator ait = AlienDependencies.begin(); diff --git a/Source/CPack/IFW/cmCPackIFWPackage.h b/Source/CPack/IFW/cmCPackIFWPackage.h index 579eeb8..739ae3e 100644 --- a/Source/CPack/IFW/cmCPackIFWPackage.h +++ b/Source/CPack/IFW/cmCPackIFWPackage.h @@ -99,6 +99,9 @@ public: /// List of license agreements to be accepted by the installing user std::vector<std::string> Licenses; + /// List of pages to load + std::vector<std::string> UserInterfaces; + /// Priority of the component in the tree std::string SortingPriority; diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index d6b58f2..e6aba89 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -14,6 +14,7 @@ #include "cmCPackComponentGroup.h" #include "cmCPackLog.h" +#include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" #include "cmGlobalGenerator.h" #include "cmMakefile.h" @@ -163,6 +164,14 @@ int cmCPackGenerator::PrepareNames() << std::endl); return 0; } + const char* algoSignature = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + if (algoSignature) { + if (cmCryptoHash::New(algoSignature).get() == CM_NULLPTR) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot recognize algorithm: " + << algoSignature << std::endl); + return 0; + } + } this->SetOptionIfNotSet("CPACK_REMOVE_TOPLEVEL_DIRECTORY", "1"); @@ -980,6 +989,10 @@ int cmCPackGenerator::DoPackage() return 0; } + /* Prepare checksum algorithm*/ + const char* algo = this->GetOption("CPACK_PACKAGE_CHECKSUM"); + CM_AUTO_PTR<cmCryptoHash> crypto = cmCryptoHash::New(algo ? algo : ""); + /* * Copy the generated packages to final destination * - there may be several of them @@ -992,8 +1005,9 @@ int cmCPackGenerator::DoPackage() /* now copy package one by one */ for (it = packageFileNames.begin(); it != packageFileNames.end(); ++it) { std::string tmpPF(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + std::string filename(cmSystemTools::GetFilenameName(*it)); tempPackageFileName = it->c_str(); - tmpPF += "/" + cmSystemTools::GetFilenameName(*it); + tmpPF += "/" + filename; const char* packageFileName = tmpPF.c_str(); cmCPackLogger(cmCPackLog::LOG_DEBUG, "Copy final package(s): " << (tempPackageFileName ? tempPackageFileName : "(NULL)") @@ -1009,6 +1023,23 @@ int cmCPackGenerator::DoPackage() } cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- package: " << packageFileName << " generated." << std::endl); + + /* Generate checksum file */ + if (crypto.get() != CM_NULLPTR) { + std::string hashFile(this->GetOption("CPACK_OUTPUT_FILE_PREFIX")); + hashFile += + "/" + filename.substr(0, filename.rfind(this->GetOutputExtension())); + hashFile += "." + cmSystemTools::LowerCase(algo); + cmsys::ofstream outF(hashFile.c_str()); + if (!outF) { + cmCPackLogger(cmCPackLog::LOG_ERROR, "Cannot create checksum file: " + << hashFile << std::endl); + return 0; + } + outF << crypto->HashFile(packageFileName) << " " << filename << "\n"; + cmCPackLogger(cmCPackLog::LOG_OUTPUT, "- checksum file: " + << hashFile << " generated." << std::endl); + } } return 1; diff --git a/Source/CTest/cmCTestSVN.cxx b/Source/CTest/cmCTestSVN.cxx index f680612..0832820 100644 --- a/Source/CTest/cmCTestSVN.cxx +++ b/Source/CTest/cmCTestSVN.cxx @@ -108,13 +108,8 @@ std::string cmCTestSVN::LoadInfo(SVNInfo& svninfo) void cmCTestSVN::NoteOldRevision() { - // Info for root repository - this->Repositories.push_back(SVNInfo("")); - this->RootInfo = &(this->Repositories.back()); - // Info for the external repositories - this->LoadExternals(); + this->LoadRepositories(); - // Get info for all the repositories std::list<SVNInfo>::iterator itbeg = this->Repositories.begin(); std::list<SVNInfo>::iterator itend = this->Repositories.end(); for (; itbeg != itend; itbeg++) { @@ -134,7 +129,8 @@ void cmCTestSVN::NoteOldRevision() void cmCTestSVN::NoteNewRevision() { - // Get info for the external repositories + this->LoadRepositories(); + std::list<SVNInfo>::iterator itbeg = this->Repositories.begin(); std::list<SVNInfo>::iterator itend = this->Repositories.end(); for (; itbeg != itend; itbeg++) { @@ -534,8 +530,13 @@ private: } }; -void cmCTestSVN::LoadExternals() +void cmCTestSVN::LoadRepositories() { + // Info for root repository + this->Repositories.clear(); + this->Repositories.push_back(SVNInfo("")); + this->RootInfo = &(this->Repositories.back()); + // Run "svn status" to get the list of external repositories std::vector<const char*> svn_status; svn_status.push_back("status"); diff --git a/Source/CTest/cmCTestSVN.h b/Source/CTest/cmCTestSVN.h index 6f2374d..2301b10 100644 --- a/Source/CTest/cmCTestSVN.h +++ b/Source/CTest/cmCTestSVN.h @@ -86,7 +86,7 @@ private: SVNInfo* RootInfo; std::string LoadInfo(SVNInfo& svninfo); - void LoadExternals(); + void LoadRepositories(); void LoadModifications() CM_OVERRIDE; void LoadRevisions() CM_OVERRIDE; void LoadRevisions(SVNInfo& svninfo); diff --git a/Source/Checks/cm_cxx_features.cmake b/Source/Checks/cm_cxx_features.cmake index 6fde7b6..c6a532f 100644 --- a/Source/Checks/cm_cxx_features.cmake +++ b/Source/Checks/cm_cxx_features.cmake @@ -32,8 +32,13 @@ function(cm_check_cxx_feature name) endfunction() if(CMAKE_CXX_STANDARD) + cm_check_cxx_feature(make_unique) + if(CMake_HAVE_CXX_MAKE_UNIQUE) + set(CMake_HAVE_CXX_UNIQUE_PTR 1) + endif() cm_check_cxx_feature(nullptr) cm_check_cxx_feature(override) + cm_check_cxx_feature(unique_ptr) cm_check_cxx_feature(unordered_map) cm_check_cxx_feature(unordered_set) endif() diff --git a/Source/Checks/cm_cxx_make_unique.cxx b/Source/Checks/cm_cxx_make_unique.cxx new file mode 100644 index 0000000..a3ff68f --- /dev/null +++ b/Source/Checks/cm_cxx_make_unique.cxx @@ -0,0 +1,6 @@ +#include <memory> +int main() +{ + std::unique_ptr<int> u = std::make_unique<int>(0); + return *u; +} diff --git a/Source/Checks/cm_cxx_unique_ptr.cxx b/Source/Checks/cm_cxx_unique_ptr.cxx new file mode 100644 index 0000000..a9d4ce5 --- /dev/null +++ b/Source/Checks/cm_cxx_unique_ptr.cxx @@ -0,0 +1,6 @@ +#include <memory> +int main() +{ + std::unique_ptr<int> u(new int(0)); + return *u; +} diff --git a/Source/CursesDialog/cmCursesStandardIncludes.h b/Source/CursesDialog/cmCursesStandardIncludes.h index 4929958..1d8d7c6 100644 --- a/Source/CursesDialog/cmCursesStandardIncludes.h +++ b/Source/CursesDialog/cmCursesStandardIncludes.h @@ -14,10 +14,6 @@ #include <cmConfigure.h> -#if defined(__sun__) && defined(__GNUC__) -#define _MSE_INT_H -#endif - #if defined(__hpux) #define _BOOL_DEFINED #include <sys/time.h> diff --git a/Source/CursesDialog/form/form.h b/Source/CursesDialog/form/form.h index 1219cb5..b65a3ca 100644 --- a/Source/CursesDialog/form/form.h +++ b/Source/CursesDialog/form/form.h @@ -33,10 +33,6 @@ #ifndef FORM_H #define FORM_H -#if defined(__sun__) && defined(__GNUC__) - #define _MSE_INT_H -#endif - #include <cmFormConfigure.h> /* figure out which curses.h to include */ diff --git a/Source/QtDialog/CMakeSetupDialog.cxx b/Source/QtDialog/CMakeSetupDialog.cxx index 5b84597..14ce3f7 100644 --- a/Source/QtDialog/CMakeSetupDialog.cxx +++ b/Source/QtDialog/CMakeSetupDialog.cxx @@ -14,6 +14,7 @@ #include <QCloseEvent> #include <QCoreApplication> +#include <QDesktopServices> #include <QDialogButtonBox> #include <QDragEnterEvent> #include <QFileDialog> @@ -227,6 +228,8 @@ void CMakeSetupDialog::initialize() QObject::connect(this->GenerateButton, SIGNAL(clicked(bool)), this, SLOT(doGenerate())); + QObject::connect(this->OpenProjectButton, SIGNAL(clicked(bool)), this, + SLOT(doOpenProject())); QObject::connect(this->BrowseSourceDirectoryButton, SIGNAL(clicked(bool)), this, SLOT(doSourceBrowse())); @@ -499,6 +502,26 @@ void CMakeSetupDialog::doGenerate() this->ConfigureNeeded = true; } +QString CMakeSetupDialog::getProjectFilename() +{ + QStringList nameFilter; + nameFilter << "*.sln" + << "*.xcodeproj"; + QDir directory(this->BinaryDirectory->currentText()); + QStringList nlnFile = directory.entryList(nameFilter); + + if (nlnFile.count() == 1) { + return this->BinaryDirectory->currentText() + "/" + nlnFile.at(0); + } + + return QString(); +} + +void CMakeSetupDialog::doOpenProject() +{ + QDesktopServices::openUrl(QUrl::fromLocalFile(this->getProjectFilename())); +} + void CMakeSetupDialog::closeEvent(QCloseEvent* e) { // prompt for close if there are unsaved changes, and we're not busy @@ -617,6 +640,11 @@ void CMakeSetupDialog::updateBinaryDirectory(const QString& dir) this->BinaryDirectory->setEditText(dir); this->BinaryDirectory->blockSignals(false); } + if (!this->getProjectFilename().isEmpty()) { + this->OpenProjectButton->setEnabled(true); + } else { + this->OpenProjectButton->setEnabled(false); + } } void CMakeSetupDialog::doBinaryBrowse() @@ -1002,22 +1030,28 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) if (s == Interrupting) { this->ConfigureButton->setEnabled(false); this->GenerateButton->setEnabled(false); + this->OpenProjectButton->setEnabled(false); } else if (s == Configuring) { this->setEnabledState(false); this->GenerateButton->setEnabled(false); this->GenerateAction->setEnabled(false); + this->OpenProjectButton->setEnabled(false); this->ConfigureButton->setText(tr("&Stop")); } else if (s == Generating) { this->CacheModified = false; this->setEnabledState(false); this->ConfigureButton->setEnabled(false); this->GenerateAction->setEnabled(false); + this->OpenProjectButton->setEnabled(false); this->GenerateButton->setText(tr("&Stop")); } else if (s == ReadyConfigure) { this->setEnabledState(true); this->GenerateButton->setEnabled(true); this->GenerateAction->setEnabled(true); this->ConfigureButton->setEnabled(true); + if (!this->getProjectFilename().isEmpty()) { + this->OpenProjectButton->setEnabled(true); + } this->ConfigureButton->setText(tr("&Configure")); this->GenerateButton->setText(tr("&Generate")); } else if (s == ReadyGenerate) { @@ -1025,6 +1059,9 @@ void CMakeSetupDialog::enterState(CMakeSetupDialog::State s) this->GenerateButton->setEnabled(true); this->GenerateAction->setEnabled(true); this->ConfigureButton->setEnabled(true); + if (!this->getProjectFilename().isEmpty()) { + this->OpenProjectButton->setEnabled(true); + } this->ConfigureButton->setText(tr("&Configure")); this->GenerateButton->setText(tr("&Generate")); } diff --git a/Source/QtDialog/CMakeSetupDialog.h b/Source/QtDialog/CMakeSetupDialog.h index 2a4ea7a..992de01 100644 --- a/Source/QtDialog/CMakeSetupDialog.h +++ b/Source/QtDialog/CMakeSetupDialog.h @@ -41,6 +41,8 @@ protected slots: void initialize(); void doConfigure(); void doGenerate(); + QString getProjectFilename(); + void doOpenProject(); void doInstallForCommandLine(); void doHelp(); void doAbout(); diff --git a/Source/QtDialog/CMakeSetupDialog.ui b/Source/QtDialog/CMakeSetupDialog.ui index b04bd93..8d8e0cd 100644 --- a/Source/QtDialog/CMakeSetupDialog.ui +++ b/Source/QtDialog/CMakeSetupDialog.ui @@ -238,6 +238,13 @@ </property> </widget> </item> + <item> + <widget class="QPushButton" name="OpenProjectButton"> + <property name="text"> + <string>Open &Project</string> + </property> + </widget> + </item> <item> <widget class="QLabel" name="Generator"> <property name="text"> diff --git a/Source/cmAddCompileOptionsCommand.cxx b/Source/cmAddCompileOptionsCommand.cxx index 2223cf4..cbba831 100644 --- a/Source/cmAddCompileOptionsCommand.cxx +++ b/Source/cmAddCompileOptionsCommand.cxx @@ -14,7 +14,7 @@ bool cmAddCompileOptionsCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmAddCustomCommandCommand.cxx b/Source/cmAddCustomCommandCommand.cxx index 2c4a4ca..2e28498 100644 --- a/Source/cmAddCustomCommandCommand.cxx +++ b/Source/cmAddCustomCommandCommand.cxx @@ -263,8 +263,8 @@ bool cmAddCustomCommandCommand::InitialPass( // No command for this output exists. std::ostringstream e; - e << "given APPEND option with output \"" << output[0] - << "\" which is not already a custom command output."; + e << "given APPEND option with output\n\"" << output[0] + << "\"\nwhich is not already a custom command output."; this->SetError(e.str()); return false; } diff --git a/Source/cmAddCustomTargetCommand.cxx b/Source/cmAddCustomTargetCommand.cxx index 9dc7c59..8e14966 100644 --- a/Source/cmAddCustomTargetCommand.cxx +++ b/Source/cmAddCustomTargetCommand.cxx @@ -18,7 +18,7 @@ bool cmAddCustomTargetCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmAddDefinitionsCommand.cxx b/Source/cmAddDefinitionsCommand.cxx index 2d0d026..5f2b32f 100644 --- a/Source/cmAddDefinitionsCommand.cxx +++ b/Source/cmAddDefinitionsCommand.cxx @@ -16,7 +16,7 @@ bool cmAddDefinitionsCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { // it is OK to have no arguments - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmAddLibraryCommand.cxx b/Source/cmAddLibraryCommand.cxx index 4516ed2..5a40050 100644 --- a/Source/cmAddLibraryCommand.cxx +++ b/Source/cmAddLibraryCommand.cxx @@ -18,7 +18,7 @@ bool cmAddLibraryCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmAddSubDirectoryCommand.cxx b/Source/cmAddSubDirectoryCommand.cxx index 63a9051..1a781cc 100644 --- a/Source/cmAddSubDirectoryCommand.cxx +++ b/Source/cmAddSubDirectoryCommand.cxx @@ -15,7 +15,7 @@ bool cmAddSubDirectoryCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmBuildCommand.cxx b/Source/cmBuildCommand.cxx index 9830867..6146053 100644 --- a/Source/cmBuildCommand.cxx +++ b/Source/cmBuildCommand.cxx @@ -27,7 +27,7 @@ bool cmBuildCommand::InitialPass(std::vector<std::string> const& args, bool cmBuildCommand::MainSignature(std::vector<std::string> const& args) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("requires at least one argument naming a CMake variable"); return false; } diff --git a/Source/cmBuildNameCommand.cxx b/Source/cmBuildNameCommand.cxx index 27234d7..3d02034 100644 --- a/Source/cmBuildNameCommand.cxx +++ b/Source/cmBuildNameCommand.cxx @@ -22,7 +22,7 @@ bool cmBuildNameCommand::InitialPass(std::vector<std::string> const& args, "The build_name command should not be called; see CMP0036.")) { return true; } - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index fdbd5e7..6ff7575 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -42,9 +42,9 @@ bool cmCMakeHostSystemInformationCommand::InitialPass( result_list += ";"; } std::string value; - if (!this->GetValue(info, key, value)) + if (!this->GetValue(info, key, value)) { return false; - + } result_list += value; } diff --git a/Source/cmCMakePolicyCommand.cxx b/Source/cmCMakePolicyCommand.cxx index 07e0885..d29e208 100644 --- a/Source/cmCMakePolicyCommand.cxx +++ b/Source/cmCMakePolicyCommand.cxx @@ -17,30 +17,34 @@ bool cmCMakePolicyCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("requires at least one argument."); return false; } if (args[0] == "SET") { return this->HandleSetMode(args); - } else if (args[0] == "GET") { + } + if (args[0] == "GET") { return this->HandleGetMode(args); - } else if (args[0] == "PUSH") { + } + if (args[0] == "PUSH") { if (args.size() > 1) { this->SetError("PUSH may not be given additional arguments."); return false; } this->Makefile->PushPolicy(); return true; - } else if (args[0] == "POP") { + } + if (args[0] == "POP") { if (args.size() > 1) { this->SetError("POP may not be given additional arguments."); return false; } this->Makefile->PopPolicy(); return true; - } else if (args[0] == "VERSION") { + } + if (args[0] == "VERSION") { return this->HandleVersionMode(args); } @@ -148,7 +152,8 @@ bool cmCMakePolicyCommand::HandleVersionMode( if (args.size() <= 1) { this->SetError("VERSION not given an argument"); return false; - } else if (args.size() >= 3) { + } + if (args.size() >= 3) { this->SetError("VERSION given too many arguments"); return false; } diff --git a/Source/cmCPluginAPI.cxx b/Source/cmCPluginAPI.cxx index f97791a..3d7839b 100644 --- a/Source/cmCPluginAPI.cxx +++ b/Source/cmCPluginAPI.cxx @@ -524,9 +524,8 @@ void CCONV* cmGetSource(void* arg, const char* name) i = cmCPluginAPISourceFiles.insert(entry).first; } return (void*)i->second; - } else { - return CM_NULLPTR; } + return CM_NULLPTR; } void* CCONV cmAddSource(void* arg, void* arg2) @@ -574,12 +573,11 @@ const char* CCONV cmSourceFileGetProperty(void* arg, const char* prop) cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { return rsf->GetProperty(prop); - } else { - if (!strcmp(prop, "LOCATION")) { - return sf->FullPath.c_str(); - } - return sf->Properties.GetPropertyValue(prop); } + if (!strcmp(prop, "LOCATION")) { + return sf->FullPath.c_str(); + } + return sf->Properties.GetPropertyValue(prop); } int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) @@ -587,9 +585,8 @@ int CCONV cmSourceFileGetPropertyAsBool(void* arg, const char* prop) cmCPluginAPISourceFile* sf = static_cast<cmCPluginAPISourceFile*>(arg); if (cmSourceFile* rsf = sf->RealSourceFile) { return rsf->GetPropertyAsBool(prop) ? 1 : 0; - } else { - return cmSystemTools::IsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0; } + return cmSystemTools::IsOn(cmSourceFileGetProperty(arg, prop)) ? 1 : 0; } void CCONV cmSourceFileSetProperty(void* arg, const char* prop, diff --git a/Source/cmCommandArgumentsHelper.cxx b/Source/cmCommandArgumentsHelper.cxx index 1345bd5..b8fe365 100644 --- a/Source/cmCommandArgumentsHelper.cxx +++ b/Source/cmCommandArgumentsHelper.cxx @@ -57,14 +57,7 @@ bool cmCommandArgument::MayFollow(const cmCommandArgument* current) const if (this->ArgumentsBeforeEmpty) { return true; } - - std::set<const cmCommandArgument*>::const_iterator argIt = - this->ArgumentsBefore.find(current); - if (argIt != this->ArgumentsBefore.end()) { - return true; - } - - return false; + return this->ArgumentsBefore.find(current) != this->ArgumentsBefore.end(); } bool cmCommandArgument::KeyMatches(const std::string& key) const diff --git a/Source/cmCommonTargetGenerator.cxx b/Source/cmCommonTargetGenerator.cxx index 6167e2c..fdf0b0e 100644 --- a/Source/cmCommonTargetGenerator.cxx +++ b/Source/cmCommonTargetGenerator.cxx @@ -47,13 +47,6 @@ std::string const& cmCommonTargetGenerator::GetConfigName() const return this->ConfigName; } -std::string cmCommonTargetGenerator::Convert( - std::string const& source, cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output) -{ - return this->LocalGenerator->Convert(source, relative, output); -} - const char* cmCommonTargetGenerator::GetFeature(const std::string& feature) { return this->GeneratorTarget->GetFeature(feature, this->ConfigName); @@ -204,8 +197,9 @@ std::string cmCommonTargetGenerator::GetManifests() std::vector<std::string> manifests; for (std::vector<cmSourceFile const*>::iterator mi = manifest_srcs.begin(); mi != manifest_srcs.end(); ++mi) { - manifests.push_back(this->Convert( - (*mi)->GetFullPath(), this->LocalGenerator->GetWorkingDirectory(), + manifests.push_back(this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetWorkingDirectory(), (*mi)->GetFullPath()), cmOutputConverter::SHELL)); } diff --git a/Source/cmCommonTargetGenerator.h b/Source/cmCommonTargetGenerator.h index b433c18..4c52fe5 100644 --- a/Source/cmCommonTargetGenerator.h +++ b/Source/cmCommonTargetGenerator.h @@ -57,10 +57,6 @@ protected: // The windows module definition source file (.def), if any. cmSourceFile const* ModuleDefinitionFile; - std::string Convert(std::string const& source, - cmOutputConverter::RelativeRoot relative, - cmOutputConverter::OutputFormat output); - void AppendFortranFormatFlags(std::string& flags, cmSourceFile const& source); diff --git a/Source/cmConditionEvaluator.cxx b/Source/cmConditionEvaluator.cxx index 94f03e8..f78e840 100644 --- a/Source/cmConditionEvaluator.cxx +++ b/Source/cmConditionEvaluator.cxx @@ -85,7 +85,7 @@ bool cmConditionEvaluator::IsTrue( errorString = ""; // handle empty invocation - if (args.size() < 1) { + if (args.empty()) { return false; } @@ -249,20 +249,19 @@ bool cmConditionEvaluator::GetBooleanValueOld( // Old IsTrue behavior for single argument. if (arg == "0") { return false; - } else if (arg == "1") { + } + if (arg == "1") { return true; - } else { - const char* def = this->GetDefinitionIfUnquoted(arg); - return !cmSystemTools::IsOff(def); } - } else { - // Old GetVariableOrNumber behavior. const char* def = this->GetDefinitionIfUnquoted(arg); - if (!def && atoi(arg.c_str())) { - def = arg.c_str(); - } return !cmSystemTools::IsOff(def); } + // Old GetVariableOrNumber behavior. + const char* def = this->GetDefinitionIfUnquoted(arg); + if (!def && atoi(arg.c_str())) { + def = arg.c_str(); + } + return !cmSystemTools::IsOff(def); } //========================================================================= @@ -274,7 +273,8 @@ bool cmConditionEvaluator::GetBooleanValueWithAutoDereference( // Use the policy if it is set. if (this->Policy12Status == cmPolicies::NEW) { return GetBooleanValue(newArg); - } else if (this->Policy12Status == cmPolicies::OLD) { + } + if (this->Policy12Status == cmPolicies::OLD) { return GetBooleanValueOld(newArg, oneArg); } diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index ccea22d..8365367 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -30,8 +30,10 @@ #cmakedefine CMAKE_USE_MACH_PARSER #cmakedefine CMAKE_USE_LIBUV #cmakedefine CMAKE_ENCODING_UTF8 +#cmakedefine CMake_HAVE_CXX_MAKE_UNIQUE #cmakedefine CMake_HAVE_CXX_NULLPTR #cmakedefine CMake_HAVE_CXX_OVERRIDE +#cmakedefine CMake_HAVE_CXX_UNIQUE_PTR #cmakedefine CMake_HAVE_CXX_UNORDERED_MAP #cmakedefine CMake_HAVE_CXX_UNORDERED_SET #define CMAKE_BIN_DIR "/@CMAKE_BIN_DIR@" diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index e9367b1..3fdf35a 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -565,9 +565,8 @@ int cmCoreTryCompile::TryCompileCode(std::vector<std::string> const& argv, if (copyFileError.empty()) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, emsg.str()); return -1; - } else { - copyFileErrorMessage = emsg.str(); } + copyFileErrorMessage = emsg.str(); } } diff --git a/Source/cmDefinePropertyCommand.cxx b/Source/cmDefinePropertyCommand.cxx index 484a970..3589529 100644 --- a/Source/cmDefinePropertyCommand.cxx +++ b/Source/cmDefinePropertyCommand.cxx @@ -17,7 +17,7 @@ bool cmDefinePropertyCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmDependsC.cxx b/Source/cmDependsC.cxx index fbbf42f..3296ffc 100644 --- a/Source/cmDependsC.cxx +++ b/Source/cmDependsC.cxx @@ -239,19 +239,18 @@ bool cmDependsC::WriteDependencies(const std::set<std::string>& sources, // written by the original local generator for this directory // convert the dependencies to paths relative to the home output // directory. We must do the same here. - std::string obj_i = this->LocalGenerator->ConvertToRelativePath( - obj, cmOutputConverter::HOME_OUTPUT); - std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( - obj_i, cmOutputConverter::MAKERULE); + std::string binDir = this->LocalGenerator->GetBinaryDirectory(); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath(binDir, obj); + std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i.c_str()); internalDepends << obj_i << std::endl; for (std::set<std::string>::const_iterator i = dependencies.begin(); i != dependencies.end(); ++i) { - makeDepends << obj_m << ": " - << this->LocalGenerator->Convert( - *i, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) - << std::endl; + makeDepends + << obj_m << ": " + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, *i).c_str()) + << std::endl; internalDepends << " " << *i << std::endl; } makeDepends << std::endl; diff --git a/Source/cmDependsFortran.cxx b/Source/cmDependsFortran.cxx index eb4c1ec..ba0617f 100644 --- a/Source/cmDependsFortran.cxx +++ b/Source/cmDependsFortran.cxx @@ -189,6 +189,8 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, cmGeneratedFileStream fcStream(fcName.c_str()); fcStream << "# Remove fortran modules provided by this target.\n"; fcStream << "FILE(REMOVE"; + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); for (std::set<std::string>::const_iterator i = provides.begin(); i != provides.end(); ++i) { std::string mod_upper = mod_dir; @@ -205,16 +207,16 @@ bool cmDependsFortran::Finalize(std::ostream& makeDepends, stamp += ".mod.stamp"; fcStream << "\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( - mod_lower, cmOutputConverter::START_OUTPUT) + << this->LocalGenerator->ConvertToRelativePath(currentBinDir, + mod_lower) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( - mod_upper, cmOutputConverter::START_OUTPUT) + << this->LocalGenerator->ConvertToRelativePath(currentBinDir, + mod_upper) << "\"\n"; fcStream << " \"" - << this->LocalGenerator->ConvertToRelativePath( - stamp, cmOutputConverter::START_OUTPUT) + << this->LocalGenerator->ConvertToRelativePath(currentBinDir, + stamp) << "\"\n"; } fcStream << " )\n"; @@ -329,19 +331,18 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, const char* src = info.Source.c_str(); // Write the include dependencies to the output stream. - std::string obj_i = this->LocalGenerator->ConvertToRelativePath( - obj, cmOutputConverter::HOME_OUTPUT); - std::string obj_m = this->LocalGenerator->ConvertToOutputFormat( - obj_i, cmOutputConverter::MAKERULE); + std::string binDir = this->LocalGenerator->GetBinaryDirectory(); + std::string obj_i = this->LocalGenerator->ConvertToRelativePath(binDir, obj); + std::string obj_m = cmSystemTools::ConvertToOutputPath(obj_i.c_str()); internalDepends << obj_i << std::endl; internalDepends << " " << src << std::endl; for (std::set<std::string>::const_iterator i = info.Includes.begin(); i != info.Includes.end(); ++i) { - makeDepends << obj_m << ": " - << this->LocalGenerator->Convert( - *i, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) - << std::endl; + makeDepends + << obj_m << ": " + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, *i).c_str()) + << std::endl; internalDepends << " " << *i << std::endl; } makeDepends << std::endl; @@ -366,8 +367,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, proxy += "/"; proxy += *i; proxy += ".mod.proxy"; - proxy = this->LocalGenerator->Convert( - proxy, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE); + proxy = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, proxy).c_str()); // since we require some things add them to our list of requirements makeDepends << obj_m << ".requires: " << proxy << std::endl; @@ -382,17 +383,17 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, } if (!required->second.empty()) { // This module is known. Depend on its timestamp file. - std::string stampFile = this->LocalGenerator->Convert( - required->second, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE); + std::string stampFile = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, required->second) + .c_str()); makeDepends << obj_m << ": " << stampFile << "\n"; } else { // This module is not known to CMake. Try to locate it where // the compiler will and depend on that. std::string module; if (this->FindModule(*i, module)) { - module = this->LocalGenerator->Convert( - module, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE); + module = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, module).c_str()); makeDepends << obj_m << ": " << module << "\n"; } } @@ -405,8 +406,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, proxy += "/"; proxy += *i; proxy += ".mod.proxy"; - proxy = this->LocalGenerator->Convert( - proxy, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE); + proxy = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, proxy).c_str()); makeDepends << proxy << ": " << obj_m << ".provides" << std::endl; } @@ -427,14 +428,16 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, std::string modFile = mod_dir; modFile += "/"; modFile += *i; - modFile = this->LocalGenerator->Convert( - modFile, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::SHELL); + modFile = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath(binDir, modFile), + cmOutputConverter::SHELL); std::string stampFile = stamp_dir; stampFile += "/"; stampFile += m; stampFile += ".mod.stamp"; - stampFile = this->LocalGenerator->Convert( - stampFile, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::SHELL); + stampFile = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath(binDir, stampFile), + cmOutputConverter::SHELL); makeDepends << "\t$(CMAKE_COMMAND) -E cmake_copy_f90_mod " << modFile << " " << stampFile; cmMakefile* mf = this->LocalGenerator->GetMakefile(); @@ -453,8 +456,8 @@ bool cmDependsFortran::WriteDependenciesReal(const char* obj, // the target finishes building. std::string driver = this->TargetDirectory; driver += "/build"; - driver = this->LocalGenerator->Convert( - driver, cmOutputConverter::HOME_OUTPUT, cmOutputConverter::MAKERULE); + driver = cmSystemTools::ConvertToOutputPath( + this->LocalGenerator->ConvertToRelativePath(binDir, driver).c_str()); makeDepends << driver << ": " << obj_m << ".provides.build\n"; } diff --git a/Source/cmEnableLanguageCommand.cxx b/Source/cmEnableLanguageCommand.cxx index 0ebe778..9b7dd03 100644 --- a/Source/cmEnableLanguageCommand.cxx +++ b/Source/cmEnableLanguageCommand.cxx @@ -17,7 +17,7 @@ bool cmEnableLanguageCommand::InitialPass(std::vector<std::string> const& args, { bool optional = false; std::vector<std::string> languages; - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx index 58bbc31..284f486 100644 --- a/Source/cmExecProgramCommand.cxx +++ b/Source/cmExecProgramCommand.cxx @@ -19,7 +19,7 @@ bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index d97b25f..ab7e0cc 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -31,7 +31,7 @@ void cmExecuteProcessCommandAppend(std::vector<char>& output, const char* data, bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -159,10 +159,9 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args, if (cmds[i].empty()) { this->SetError(" given COMMAND argument with no value."); return false; - } else { - // Add the null terminating pointer to the command argument list. - cmds[i].push_back(CM_NULLPTR); } + // Add the null terminating pointer to the command argument list. + cmds[i].push_back(CM_NULLPTR); } // Parse the timeout string. diff --git a/Source/cmExportBuildAndroidMKGenerator.cxx b/Source/cmExportBuildAndroidMKGenerator.cxx new file mode 100644 index 0000000..41d2f7a --- /dev/null +++ b/Source/cmExportBuildAndroidMKGenerator.cxx @@ -0,0 +1,193 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmExportBuildAndroidMKGenerator.h" + +#include "cmExportSet.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmTargetExport.h" + +cmExportBuildAndroidMKGenerator::cmExportBuildAndroidMKGenerator() +{ + this->LG = CM_NULLPTR; + this->ExportSet = CM_NULLPTR; +} + +void cmExportBuildAndroidMKGenerator::GenerateImportHeaderCode( + std::ostream& os, const std::string&) +{ + os << "LOCAL_PATH := $(call my-dir)\n\n"; +} + +void cmExportBuildAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) +{ +} + +void cmExportBuildAndroidMKGenerator::GenerateExpectedTargetsCode( + std::ostream&, const std::string&) +{ +} + +void cmExportBuildAndroidMKGenerator::GenerateImportTargetCode( + std::ostream& os, const cmGeneratorTarget* target) +{ + std::string targetName = this->Namespace; + targetName += target->GetExportName(); + os << "include $(CLEAR_VARS)\n"; + os << "LOCAL_MODULE := "; + os << targetName << "\n"; + os << "LOCAL_SRC_FILES := "; + std::string path = + cmSystemTools::ConvertToOutputPath(target->GetFullPath().c_str()); + os << path << "\n"; +} + +void cmExportBuildAndroidMKGenerator::GenerateImportPropertyCode( + std::ostream&, const std::string&, cmGeneratorTarget const*, + ImportPropertyMap const&) +{ +} + +void cmExportBuildAndroidMKGenerator::GenerateMissingTargetsCheckCode( + std::ostream&, const std::vector<std::string>&) +{ +} + +void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( + const cmGeneratorTarget* target, std::ostream& os, + const ImportPropertyMap& properties) +{ + std::string config = ""; + if (!this->Configurations.empty()) { + config = this->Configurations[0]; + } + cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( + target, os, properties, cmExportBuildAndroidMKGenerator::BUILD, config); +} + +void cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( + const cmGeneratorTarget* target, std::ostream& os, + const ImportPropertyMap& properties, GenerateType type, + std::string const& config) +{ + const bool newCMP0022Behavior = + target->GetPolicyStatusCMP0022() != cmPolicies::WARN && + target->GetPolicyStatusCMP0022() != cmPolicies::OLD; + if (!newCMP0022Behavior) { + std::ostringstream w; + if (type == cmExportBuildAndroidMKGenerator::BUILD) { + w << "export(TARGETS ... ANDROID_MK) called with policy CMP0022"; + } else { + w << "install( EXPORT_ANDROID_MK ...) called with policy CMP0022"; + } + w << " set to OLD for target " << target->Target->GetName() << ". " + << "The export will only work with CMP0022 set to NEW."; + target->Makefile->IssueMessage(cmake::AUTHOR_WARNING, w.str()); + } + if (!properties.empty()) { + os << "LOCAL_CPP_FEATURES := rtti exceptions\n"; + for (ImportPropertyMap::const_iterator pi = properties.begin(); + pi != properties.end(); ++pi) { + if (pi->first == "INTERFACE_COMPILE_OPTIONS") { + os << "LOCAL_CPP_FEATURES += "; + os << (pi->second) << "\n"; + } else if (pi->first == "INTERFACE_LINK_LIBRARIES") { + // need to look at list in pi->second and see if static or shared + // FindTargetToLink + // target->GetLocalGenerator()->FindGeneratorTargetToUse() + // then add to LOCAL_CPPFLAGS + std::vector<std::string> libraries; + cmSystemTools::ExpandListArgument(pi->second, libraries); + std::string staticLibs; + std::string sharedLibs; + std::string ldlibs; + for (std::vector<std::string>::iterator i = libraries.begin(); + i != libraries.end(); ++i) { + cmGeneratorTarget* gt = + target->GetLocalGenerator()->FindGeneratorTargetToUse(*i); + if (gt) { + + if (gt->GetType() == cmState::SHARED_LIBRARY || + gt->GetType() == cmState::MODULE_LIBRARY) { + sharedLibs += " " + *i; + } else { + staticLibs += " " + *i; + } + } else { + // evaluate any generator expressions with the current + // build type of the makefile + cmGeneratorExpression ge; + CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(*i); + std::string evaluated = + cge->Evaluate(target->GetLocalGenerator(), config); + bool relpath = false; + if (type == cmExportBuildAndroidMKGenerator::INSTALL) { + relpath = i->substr(0, 3) == "../"; + } + // check for full path or if it already has a -l, or + // in the case of an install check for relative paths + // if it is full or a link library then use string directly + if (cmSystemTools::FileIsFullPath(evaluated) || + evaluated.substr(0, 2) == "-l" || relpath) { + ldlibs += " " + evaluated; + // if it is not a path and does not have a -l then add -l + } else if (!evaluated.empty()) { + ldlibs += " -l" + evaluated; + } + } + } + if (!sharedLibs.empty()) { + os << "LOCAL_SHARED_LIBRARIES :=" << sharedLibs << "\n"; + } + if (!staticLibs.empty()) { + os << "LOCAL_STATIC_LIBRARIES :=" << staticLibs << "\n"; + } + if (!ldlibs.empty()) { + os << "LOCAL_EXPORT_LDLIBS :=" << ldlibs << "\n"; + } + } else if (pi->first == "INTERFACE_INCLUDE_DIRECTORIES") { + std::string includes = pi->second; + std::vector<std::string> includeList; + cmSystemTools::ExpandListArgument(includes, includeList); + os << "LOCAL_EXPORT_C_INCLUDES := "; + std::string end; + for (std::vector<std::string>::iterator i = includeList.begin(); + i != includeList.end(); ++i) { + os << end << *i; + end = "\\\n"; + } + os << "\n"; + } else { + os << "# " << pi->first << " " << (pi->second) << "\n"; + } + } + } + switch (target->GetType()) { + case cmState::SHARED_LIBRARY: + case cmState::MODULE_LIBRARY: + os << "include $(PREBUILT_SHARED_LIBRARY)\n"; + break; + case cmState::STATIC_LIBRARY: + os << "include $(PREBUILT_STATIC_LIBRARY)\n"; + break; + case cmState::EXECUTABLE: + case cmState::UTILITY: + case cmState::OBJECT_LIBRARY: + case cmState::GLOBAL_TARGET: + case cmState::INTERFACE_LIBRARY: + case cmState::UNKNOWN_LIBRARY: + break; + } + os << "\n"; +} diff --git a/Source/cmExportBuildAndroidMKGenerator.h b/Source/cmExportBuildAndroidMKGenerator.h new file mode 100644 index 0000000..d15245e --- /dev/null +++ b/Source/cmExportBuildAndroidMKGenerator.h @@ -0,0 +1,69 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportBuildAndroidMKGenerator_h +#define cmExportBuildAndroidMKGenerator_h + +#include "cmExportBuildFileGenerator.h" +#include "cmListFileCache.h" + +class cmExportSet; + +/** \class cmExportBuildAndroidMKGenerator + * \brief Generate a file exporting targets from a build tree. + * + * cmExportBuildAndroidMKGenerator generates a file exporting targets from + * a build tree. This exports the targets to the Android ndk build tool + * makefile format for prebuilt libraries. + * + * This is used to implement the EXPORT() command. + */ +class cmExportBuildAndroidMKGenerator : public cmExportBuildFileGenerator +{ +public: + cmExportBuildAndroidMKGenerator(); + // this is so cmExportInstallAndroidMKGenerator can share this + // function as they are almost the same + enum GenerateType + { + BUILD, + INSTALL + }; + static void GenerateInterfaceProperties(cmGeneratorTarget const* target, + std::ostream& os, + const ImportPropertyMap& properties, + GenerateType type, + std::string const& config); + +protected: + // Implement virtual methods from the superclass. + void GeneratePolicyHeaderCode(std::ostream&) CM_OVERRIDE {} + void GeneratePolicyFooterCode(std::ostream&) CM_OVERRIDE {} + void GenerateImportHeaderCode(std::ostream& os, + const std::string& config = "") CM_OVERRIDE; + void GenerateImportFooterCode(std::ostream& os) CM_OVERRIDE; + void GenerateImportTargetCode(std::ostream& os, + const cmGeneratorTarget* target) CM_OVERRIDE; + void GenerateExpectedTargetsCode( + std::ostream& os, const std::string& expectedTargets) CM_OVERRIDE; + void GenerateImportPropertyCode(std::ostream& os, const std::string& config, + cmGeneratorTarget const* target, + ImportPropertyMap const& properties) + CM_OVERRIDE; + void GenerateMissingTargetsCheckCode( + std::ostream& os, + const std::vector<std::string>& missingTargets) CM_OVERRIDE; + void GenerateInterfaceProperties( + cmGeneratorTarget const* target, std::ostream& os, + const ImportPropertyMap& properties) CM_OVERRIDE; +}; + +#endif diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index fc62492..466fad3 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -18,6 +18,7 @@ #include <cmsys/Encoding.hxx> #include <cmsys/RegularExpression.hxx> +#include "cmExportBuildAndroidMKGenerator.h" #include "cmExportBuildFileGenerator.h" #if defined(__HAIKU__) @@ -34,6 +35,7 @@ cmExportCommand::cmExportCommand() , Namespace(&Helper, "NAMESPACE", &ArgumentGroup) , Filename(&Helper, "FILE", &ArgumentGroup) , ExportOld(&Helper, "EXPORT_LINK_INTERFACE_LIBRARIES", &ArgumentGroup) + , AndroidMKFile(&Helper, "ANDROID_MK") { this->ExportSet = CM_NULLPTR; } @@ -49,7 +51,8 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, if (args[0] == "PACKAGE") { return this->HandlePackage(args); - } else if (args[0] == "EXPORT") { + } + if (args[0] == "EXPORT") { this->ExportSetName.Follows(CM_NULLPTR); this->ArgumentGroup.Follows(&this->ExportSetName); } else { @@ -66,13 +69,18 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } std::string fname; - if (!this->Filename.WasFound()) { + bool android = false; + if (this->AndroidMKFile.WasFound()) { + fname = this->AndroidMKFile.GetString(); + android = true; + } + if (!this->Filename.WasFound() && fname.empty()) { if (args[0] != "EXPORT") { this->SetError("FILE <filename> option missing."); return false; } fname = this->ExportSetName.GetString() + ".cmake"; - } else { + } else if (fname.empty()) { // Make sure the file has a .cmake extension. if (cmSystemTools::GetFilenameLastExtension(this->Filename.GetCString()) != ".cmake") { @@ -176,7 +184,12 @@ bool cmExportCommand::InitialPass(std::vector<std::string> const& args, } // Setup export file generation. - cmExportBuildFileGenerator* ebfg = new cmExportBuildFileGenerator; + cmExportBuildFileGenerator* ebfg = CM_NULLPTR; + if (android) { + ebfg = new cmExportBuildAndroidMKGenerator; + } else { + ebfg = new cmExportBuildFileGenerator; + } ebfg->SetExportFile(fname.c_str()); ebfg->SetNamespace(this->Namespace.GetCString()); ebfg->SetAppendMode(this->Append.IsEnabled()); diff --git a/Source/cmExportCommand.h b/Source/cmExportCommand.h index 0a149af..481d2c5 100644 --- a/Source/cmExportCommand.h +++ b/Source/cmExportCommand.h @@ -54,6 +54,7 @@ private: cmCAString Namespace; cmCAString Filename; cmCAEnabler ExportOld; + cmCAString AndroidMKFile; cmExportSet* ExportSet; diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index 23c77d9..c4c7d7d 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -96,24 +96,8 @@ bool cmExportFileGenerator::GenerateImportFile() } std::ostream& os = *foutPtr; - // Protect that file against use with older CMake versions. - /* clang-format off */ - os << "# Generated by CMake\n\n"; - os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n" - << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n" - << "endif()\n"; - /* clang-format on */ - - // Isolate the file policy level. - // We use 2.6 here instead of the current version because newer - // versions of CMake should be able to export files imported by 2.6 - // until the import format changes. - /* clang-format off */ - os << "cmake_policy(PUSH)\n" - << "cmake_policy(VERSION 2.6)\n"; - /* clang-format on */ - // Start with the import file header. + this->GeneratePolicyHeaderCode(os); this->GenerateImportHeaderCode(os); // Create all the imported targets. @@ -121,7 +105,7 @@ bool cmExportFileGenerator::GenerateImportFile() // End with the import file footer. this->GenerateImportFooterCode(os); - os << "cmake_policy(POP)\n"; + this->GeneratePolicyFooterCode(os); return result; } @@ -832,6 +816,31 @@ void cmExportFileGenerator::SetImportLinkProperty( properties[prop] = link_entries; } +void cmExportFileGenerator::GeneratePolicyHeaderCode(std::ostream& os) +{ + // Protect that file against use with older CMake versions. + /* clang-format off */ + os << "# Generated by CMake\n\n"; + os << "if(\"${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}\" LESS 2.5)\n" + << " message(FATAL_ERROR \"CMake >= 2.6.0 required\")\n" + << "endif()\n"; + /* clang-format on */ + + // Isolate the file policy level. + // We use 2.6 here instead of the current version because newer + // versions of CMake should be able to export files imported by 2.6 + // until the import format changes. + /* clang-format off */ + os << "cmake_policy(PUSH)\n" + << "cmake_policy(VERSION 2.6)\n"; + /* clang-format on */ +} + +void cmExportFileGenerator::GeneratePolicyFooterCode(std::ostream& os) +{ + os << "cmake_policy(POP)\n"; +} + void cmExportFileGenerator::GenerateImportHeaderCode(std::ostream& os, const std::string& config) { diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 354994a..d106ab7 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -78,25 +78,28 @@ protected: std::vector<std::string>& missingTargets); // Methods to implement export file code generation. - void GenerateImportHeaderCode(std::ostream& os, - const std::string& config = ""); - void GenerateImportFooterCode(std::ostream& os); + virtual void GeneratePolicyHeaderCode(std::ostream& os); + virtual void GeneratePolicyFooterCode(std::ostream& os); + virtual void GenerateImportHeaderCode(std::ostream& os, + const std::string& config = ""); + virtual void GenerateImportFooterCode(std::ostream& os); void GenerateImportVersionCode(std::ostream& os); - void GenerateImportTargetCode(std::ostream& os, - cmGeneratorTarget const* target); - void GenerateImportPropertyCode(std::ostream& os, const std::string& config, - cmGeneratorTarget const* target, - ImportPropertyMap const& properties); - void GenerateImportedFileChecksCode( + virtual void GenerateImportTargetCode(std::ostream& os, + cmGeneratorTarget const* target); + virtual void GenerateImportPropertyCode(std::ostream& os, + const std::string& config, + cmGeneratorTarget const* target, + ImportPropertyMap const& properties); + virtual void GenerateImportedFileChecksCode( std::ostream& os, cmGeneratorTarget* target, ImportPropertyMap const& properties, const std::set<std::string>& importedLocations); - void GenerateImportedFileCheckLoop(std::ostream& os); - void GenerateMissingTargetsCheckCode( + virtual void GenerateImportedFileCheckLoop(std::ostream& os); + virtual void GenerateMissingTargetsCheckCode( std::ostream& os, const std::vector<std::string>& missingTargets); - void GenerateExpectedTargetsCode(std::ostream& os, - const std::string& expectedTargets); + virtual void GenerateExpectedTargetsCode(std::ostream& os, + const std::string& expectedTargets); // Collect properties with detailed information about targets beyond // their location on disk. @@ -140,9 +143,9 @@ protected: ImportPropertyMap& properties); void PopulateCompatibleInterfaceProperties(cmGeneratorTarget* target, ImportPropertyMap& properties); - void GenerateInterfaceProperties(cmGeneratorTarget const* target, - std::ostream& os, - const ImportPropertyMap& properties); + virtual void GenerateInterfaceProperties( + cmGeneratorTarget const* target, std::ostream& os, + const ImportPropertyMap& properties); void PopulateIncludeDirectoriesInterface( cmTargetExport* target, cmGeneratorExpression::PreprocessContext preprocessRule, @@ -169,8 +172,8 @@ protected: std::vector<std::string>& missingTargets, FreeTargetsReplace replace = NoReplaceFreeTargets); - void GenerateRequiredCMakeVersion(std::ostream& os, - const char* versionString); + virtual void GenerateRequiredCMakeVersion(std::ostream& os, + const char* versionString); // The namespace in which the exports are placed in the generated file. std::string Namespace; diff --git a/Source/cmExportInstallAndroidMKGenerator.cxx b/Source/cmExportInstallAndroidMKGenerator.cxx new file mode 100644 index 0000000..10ba6ee --- /dev/null +++ b/Source/cmExportInstallAndroidMKGenerator.cxx @@ -0,0 +1,146 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmExportInstallAndroidMKGenerator.h" + +#include "cmAlgorithms.h" +#include "cmExportBuildAndroidMKGenerator.h" +#include "cmExportSet.h" +#include "cmExportSetMap.h" +#include "cmGeneratedFileStream.h" +#include "cmGeneratorTarget.h" +#include "cmGlobalGenerator.h" +#include "cmInstallExportGenerator.h" +#include "cmInstallTargetGenerator.h" +#include "cmLocalGenerator.h" +#include "cmTargetExport.h" + +cmExportInstallAndroidMKGenerator::cmExportInstallAndroidMKGenerator( + cmInstallExportGenerator* iegen) + : cmExportInstallFileGenerator(iegen) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportHeaderCode( + std::ostream& os, const std::string&) +{ + std::string installDir = this->IEGen->GetDestination(); + os << "LOCAL_PATH := $(call my-dir)\n"; + size_t numDotDot = cmSystemTools::CountChar(installDir.c_str(), '/'); + numDotDot += (installDir.size() > 0) ? 1 : 0; + std::string path; + for (size_t n = 0; n < numDotDot; n++) { + path += "/.."; + } + os << "_IMPORT_PREFIX := " + << "$(LOCAL_PATH)" << path << "\n\n"; + for (std::vector<cmTargetExport*>::const_iterator tei = + this->IEGen->GetExportSet()->GetTargetExports()->begin(); + tei != this->IEGen->GetExportSet()->GetTargetExports()->end(); ++tei) { + // Collect import properties for this target. + cmTargetExport const* te = *tei; + if (te->Target->GetType() == cmState::INTERFACE_LIBRARY) { + continue; + } + std::string dest; + if (te->LibraryGenerator) { + dest = te->LibraryGenerator->GetDestination(""); + } + if (te->ArchiveGenerator) { + dest = te->ArchiveGenerator->GetDestination(""); + } + te->Target->Target->SetProperty("__dest", dest.c_str()); + } +} + +void cmExportInstallAndroidMKGenerator::GenerateImportFooterCode(std::ostream&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportTargetCode( + std::ostream& os, const cmGeneratorTarget* target) +{ + std::string targetName = this->Namespace; + targetName += target->GetExportName(); + os << "include $(CLEAR_VARS)\n"; + os << "LOCAL_MODULE := "; + os << targetName << "\n"; + os << "LOCAL_SRC_FILES := $(_IMPORT_PREFIX)/"; + os << target->Target->GetProperty("__dest") << "/"; + std::string config = ""; + if (!this->Configurations.empty()) { + config = this->Configurations[0]; + } + os << target->GetFullName(config) << "\n"; +} + +void cmExportInstallAndroidMKGenerator::GenerateExpectedTargetsCode( + std::ostream&, const std::string&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportPropertyCode( + std::ostream&, const std::string&, cmGeneratorTarget const*, + ImportPropertyMap const&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateMissingTargetsCheckCode( + std::ostream&, const std::vector<std::string>&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateInterfaceProperties( + cmGeneratorTarget const* target, std::ostream& os, + const ImportPropertyMap& properties) +{ + std::string config = ""; + if (!this->Configurations.empty()) { + config = this->Configurations[0]; + } + cmExportBuildAndroidMKGenerator::GenerateInterfaceProperties( + target, os, properties, cmExportBuildAndroidMKGenerator::INSTALL, config); +} + +void cmExportInstallAndroidMKGenerator::LoadConfigFiles(std::ostream&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportPrefix(std::ostream&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateRequiredCMakeVersion( + std::ostream&, const char*) +{ +} + +void cmExportInstallAndroidMKGenerator::CleanupTemporaryVariables( + std::ostream&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportedFileCheckLoop( + std::ostream&) +{ +} + +void cmExportInstallAndroidMKGenerator::GenerateImportedFileChecksCode( + std::ostream&, cmGeneratorTarget*, ImportPropertyMap const&, + const std::set<std::string>&) +{ +} + +bool cmExportInstallAndroidMKGenerator::GenerateImportFileConfig( + const std::string&, std::vector<std::string>&) +{ + return true; +} diff --git a/Source/cmExportInstallAndroidMKGenerator.h b/Source/cmExportInstallAndroidMKGenerator.h new file mode 100644 index 0000000..ccfe6f8 --- /dev/null +++ b/Source/cmExportInstallAndroidMKGenerator.h @@ -0,0 +1,73 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmExportInstallAndroidMKGenerator_h +#define cmExportInstallAndroidMKGenerator_h + +#include "cmExportInstallFileGenerator.h" + +class cmInstallExportGenerator; +class cmInstallTargetGenerator; + +/** \class cmExportInstallAndroidMKGenerator + * \brief Generate a file exporting targets from an install tree. + * + * cmExportInstallAndroidMKGenerator generates files exporting targets from + * install an installation tree. The files are placed in a temporary + * location for installation by cmInstallExportGenerator. The file format + * is for the ndk build system and is a makefile fragment specifing prebuilt + * libraries to the ndk build system. + * + * This is used to implement the INSTALL(EXPORT_ANDROID_MK) command. + */ +class cmExportInstallAndroidMKGenerator : public cmExportInstallFileGenerator +{ +public: + /** Construct with the export installer that will install the + files. */ + cmExportInstallAndroidMKGenerator(cmInstallExportGenerator* iegen); + +protected: + // Implement virtual methods from the superclass. + void GeneratePolicyHeaderCode(std::ostream&) CM_OVERRIDE {} + void GeneratePolicyFooterCode(std::ostream&) CM_OVERRIDE {} + void GenerateImportHeaderCode(std::ostream& os, + const std::string& config = "") CM_OVERRIDE; + void GenerateImportFooterCode(std::ostream& os) CM_OVERRIDE; + void GenerateImportTargetCode(std::ostream& os, + const cmGeneratorTarget* target) CM_OVERRIDE; + void GenerateExpectedTargetsCode( + std::ostream& os, const std::string& expectedTargets) CM_OVERRIDE; + void GenerateImportPropertyCode(std::ostream& os, const std::string& config, + cmGeneratorTarget const* target, + ImportPropertyMap const& properties) + CM_OVERRIDE; + void GenerateMissingTargetsCheckCode( + std::ostream& os, + const std::vector<std::string>& missingTargets) CM_OVERRIDE; + void GenerateInterfaceProperties( + cmGeneratorTarget const* target, std::ostream& os, + const ImportPropertyMap& properties) CM_OVERRIDE; + void GenerateImportPrefix(std::ostream& os) CM_OVERRIDE; + void LoadConfigFiles(std::ostream&) CM_OVERRIDE; + void GenerateRequiredCMakeVersion(std::ostream& os, + const char* versionString) CM_OVERRIDE; + void CleanupTemporaryVariables(std::ostream&) CM_OVERRIDE; + void GenerateImportedFileCheckLoop(std::ostream& os) CM_OVERRIDE; + void GenerateImportedFileChecksCode( + std::ostream& os, cmGeneratorTarget* target, + ImportPropertyMap const& properties, + const std::set<std::string>& importedLocations) CM_OVERRIDE; + bool GenerateImportFileConfig(const std::string& config, + std::vector<std::string>&) CM_OVERRIDE; +}; + +#endif diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index bcadaa0..f47038f 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -75,58 +75,8 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateExpectedTargetsCode(os, expectedTargets); } - // Set an _IMPORT_PREFIX variable for import location properties - // to reference if they are relative to the install prefix. - std::string installPrefix = - this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition( - "CMAKE_INSTALL_PREFIX"); - std::string const& expDest = this->IEGen->GetDestination(); - if (cmSystemTools::FileIsFullPath(expDest)) { - // The export file is being installed to an absolute path so the - // package is not relocatable. Use the configured install prefix. - /* clang-format off */ - os << - "# The installation prefix configured by this project.\n" - "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n" - "\n"; - /* clang-format on */ - } else { - // Add code to compute the installation prefix relative to the - // import file location. - std::string absDest = installPrefix + "/" + expDest; - std::string absDestS = absDest + "/"; - os << "# Compute the installation prefix relative to this file.\n" - << "get_filename_component(_IMPORT_PREFIX" - << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; - if (cmHasLiteralPrefix(absDestS.c_str(), "/lib/") || - cmHasLiteralPrefix(absDestS.c_str(), "/lib64/") || - cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib/") || - cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib64/")) { - // Handle "/usr move" symlinks created by some Linux distros. - /* clang-format off */ - os << - "# Use original install prefix when loaded through a\n" - "# cross-prefix symbolic link such as /lib -> /usr/lib.\n" - "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n" - "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n" - "if(_realCurr STREQUAL _realOrig)\n" - " set(_IMPORT_PREFIX \"" << absDest << "\")\n" - "endif()\n" - "unset(_realOrig)\n" - "unset(_realCurr)\n"; - /* clang-format on */ - } - std::string dest = expDest; - while (!dest.empty()) { - os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" " - "PATH)\n"; - dest = cmSystemTools::GetFilenamePath(dest); - } - os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n" - << " set(_IMPORT_PREFIX \"\")\n" - << "endif()\n" - << "\n"; - } + // Compute the relative import prefix for the file + this->GenerateImportPrefix(os); std::vector<std::string> missingTargets; @@ -204,24 +154,9 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateRequiredCMakeVersion(os, "2.8.12"); } - // Now load per-configuration properties for them. - /* clang-format off */ - os << "# Load information for each installed configuration.\n" - << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n" - << "file(GLOB CONFIG_FILES \"${_DIR}/" - << this->GetConfigImportFileGlob() << "\")\n" - << "foreach(f ${CONFIG_FILES})\n" - << " include(${f})\n" - << "endforeach()\n" - << "\n"; - /* clang-format on */ + this->LoadConfigFiles(os); - // Cleanup the import prefix variable. - /* clang-format off */ - os << "# Cleanup temporary variables.\n" - << "set(_IMPORT_PREFIX)\n" - << "\n"; - /* clang-format on */ + this->CleanupTemporaryVariables(os); this->GenerateImportedFileCheckLoop(os); bool result = true; @@ -242,6 +177,86 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) return result; } +void cmExportInstallFileGenerator::GenerateImportPrefix(std::ostream& os) +{ + // Set an _IMPORT_PREFIX variable for import location properties + // to reference if they are relative to the install prefix. + std::string installPrefix = + this->IEGen->GetLocalGenerator()->GetMakefile()->GetSafeDefinition( + "CMAKE_INSTALL_PREFIX"); + std::string const& expDest = this->IEGen->GetDestination(); + if (cmSystemTools::FileIsFullPath(expDest)) { + // The export file is being installed to an absolute path so the + // package is not relocatable. Use the configured install prefix. + /* clang-format off */ + os << + "# The installation prefix configured by this project.\n" + "set(_IMPORT_PREFIX \"" << installPrefix << "\")\n" + "\n"; + /* clang-format on */ + } else { + // Add code to compute the installation prefix relative to the + // import file location. + std::string absDest = installPrefix + "/" + expDest; + std::string absDestS = absDest + "/"; + os << "# Compute the installation prefix relative to this file.\n" + << "get_filename_component(_IMPORT_PREFIX" + << " \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n"; + if (cmHasLiteralPrefix(absDestS.c_str(), "/lib/") || + cmHasLiteralPrefix(absDestS.c_str(), "/lib64/") || + cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib/") || + cmHasLiteralPrefix(absDestS.c_str(), "/usr/lib64/")) { + // Handle "/usr move" symlinks created by some Linux distros. + /* clang-format off */ + os << + "# Use original install prefix when loaded through a\n" + "# cross-prefix symbolic link such as /lib -> /usr/lib.\n" + "get_filename_component(_realCurr \"${_IMPORT_PREFIX}\" REALPATH)\n" + "get_filename_component(_realOrig \"" << absDest << "\" REALPATH)\n" + "if(_realCurr STREQUAL _realOrig)\n" + " set(_IMPORT_PREFIX \"" << absDest << "\")\n" + "endif()\n" + "unset(_realOrig)\n" + "unset(_realCurr)\n"; + /* clang-format on */ + } + std::string dest = expDest; + while (!dest.empty()) { + os << "get_filename_component(_IMPORT_PREFIX \"${_IMPORT_PREFIX}\" " + "PATH)\n"; + dest = cmSystemTools::GetFilenamePath(dest); + } + os << "if(_IMPORT_PREFIX STREQUAL \"/\")\n" + << " set(_IMPORT_PREFIX \"\")\n" + << "endif()\n" + << "\n"; + } +} + +void cmExportInstallFileGenerator::CleanupTemporaryVariables(std::ostream& os) +{ + /* clang-format off */ + os << "# Cleanup temporary variables.\n" + << "set(_IMPORT_PREFIX)\n" + << "\n"; + /* clang-format on */ +} + +void cmExportInstallFileGenerator::LoadConfigFiles(std::ostream& os) +{ + // Now load per-configuration properties for them. + /* clang-format off */ + os << "# Load information for each installed configuration.\n" + << "get_filename_component(_DIR \"${CMAKE_CURRENT_LIST_FILE}\" PATH)\n" + << "file(GLOB CONFIG_FILES \"${_DIR}/" + << this->GetConfigImportFileGlob() << "\")\n" + << "foreach(f ${CONFIG_FILES})\n" + << " include(${f})\n" + << "endforeach()\n" + << "\n"; + /* clang-format on */ +} + void cmExportInstallFileGenerator::ReplaceInstallPrefix(std::string& input) { std::string::size_type pos = 0; diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index c693dc1..63f2d40 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -80,9 +80,17 @@ protected: std::vector<std::string> FindNamespaces(cmGlobalGenerator* gg, const std::string& name); + /** Generate the relative import prefix. */ + virtual void GenerateImportPrefix(std::ostream&); + + /** Generate the relative import prefix. */ + virtual void LoadConfigFiles(std::ostream&); + + virtual void CleanupTemporaryVariables(std::ostream&); + /** Generate a per-configuration file for the targets. */ - bool GenerateImportFileConfig(const std::string& config, - std::vector<std::string>& missingTargets); + virtual bool GenerateImportFileConfig( + const std::string& config, std::vector<std::string>& missingTargets); /** Fill in properties indicating installed file locations. */ void SetImportLocationProperty(const std::string& config, diff --git a/Source/cmExportLibraryDependenciesCommand.cxx b/Source/cmExportLibraryDependenciesCommand.cxx index b422a2c..350c855 100644 --- a/Source/cmExportLibraryDependenciesCommand.cxx +++ b/Source/cmExportLibraryDependenciesCommand.cxx @@ -27,7 +27,7 @@ bool cmExportLibraryDependenciesCommand::InitialPass( "see CMP0033.")) { return true; } - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -64,7 +64,7 @@ void cmExportLibraryDependenciesCommand::ConstFinalPass() const ap->SetCopyIfDifferent(true); foutPtr = ap; } - std::ostream& fout = *foutPtr.get(); + std::ostream& fout = *foutPtr; if (!fout) { cmSystemTools::Error("Error Writing ", this->Filename.c_str()); diff --git a/Source/cmExportTryCompileFileGenerator.cxx b/Source/cmExportTryCompileFileGenerator.cxx index a0aefb8..6c31481 100644 --- a/Source/cmExportTryCompileFileGenerator.cxx +++ b/Source/cmExportTryCompileFileGenerator.cxx @@ -77,9 +77,8 @@ std::string cmExportTryCompileFileGenerator::FindTargets( CM_AUTO_PTR<cmCompiledGeneratorExpression> cge = ge.Parse(prop); - cmTarget dummyHead; - dummyHead.SetType(cmState::EXECUTABLE, "try_compile_dummy_exe"); - dummyHead.SetMakefile(tgt->Target->GetMakefile()); + cmTarget dummyHead("try_compile_dummy_exe", cmState::EXECUTABLE, + cmTarget::VisibilityNormal, tgt->Target->GetMakefile()); cmGeneratorTarget gDummyHead(&dummyHead, tgt->GetLocalGenerator()); diff --git a/Source/cmExternalMakefileProjectGenerator.h b/Source/cmExternalMakefileProjectGenerator.h index b306f19..aa614fc 100644 --- a/Source/cmExternalMakefileProjectGenerator.h +++ b/Source/cmExternalMakefileProjectGenerator.h @@ -108,7 +108,7 @@ public: } cmExternalMakefileProjectGenerator* CreateExternalMakefileProjectGenerator() - const + const CM_OVERRIDE { T* p = new T; p->SetName(GetName()); diff --git a/Source/cmExtraEclipseCDT4Generator.cxx b/Source/cmExtraEclipseCDT4Generator.cxx index 5a98e34..61f2851 100644 --- a/Source/cmExtraEclipseCDT4Generator.cxx +++ b/Source/cmExtraEclipseCDT4Generator.cxx @@ -914,7 +914,7 @@ void cmExtraEclipseCDT4Generator::CreateCProjectFile() const const std::vector<cmGeneratorTarget*> targets = (*it)->GetGeneratorTargets(); std::string subdir = (*it)->ConvertToRelativePath( - (*it)->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); + this->HomeOutputDirectory, (*it)->GetCurrentBinaryDirectory()); if (subdir == ".") { subdir = ""; } diff --git a/Source/cmFileCommand.cxx b/Source/cmFileCommand.cxx index 835b118..a13309d 100644 --- a/Source/cmFileCommand.cxx +++ b/Source/cmFileCommand.cxx @@ -104,19 +104,25 @@ bool cmFileCommand::InitialPass(std::vector<std::string> const& args, std::string subCommand = args[0]; if (subCommand == "WRITE") { return this->HandleWriteCommand(args, false); - } else if (subCommand == "APPEND") { + } + if (subCommand == "APPEND") { return this->HandleWriteCommand(args, true); - } else if (subCommand == "DOWNLOAD") { + } + if (subCommand == "DOWNLOAD") { return this->HandleDownloadCommand(args); - } else if (subCommand == "UPLOAD") { + } + if (subCommand == "UPLOAD") { return this->HandleUploadCommand(args); - } else if (subCommand == "READ") { + } + if (subCommand == "READ") { return this->HandleReadCommand(args); - } else if (subCommand == "MD5" || subCommand == "SHA1" || - subCommand == "SHA224" || subCommand == "SHA256" || - subCommand == "SHA384" || subCommand == "SHA512") { + } + if (subCommand == "MD5" || subCommand == "SHA1" || subCommand == "SHA224" || + subCommand == "SHA256" || subCommand == "SHA384" || + subCommand == "SHA512") { return this->HandleHashCommand(args); - } else if (subCommand == "STRINGS") { + } + if (subCommand == "STRINGS") { return this->HandleStringsCommand(args); } else if (subCommand == "GLOB") { return this->HandleGlobCommand(args, false); @@ -594,8 +600,9 @@ bool cmFileCommand::HandleStringsCommand(std::vector<std::string> const& args) // how many octets are there? unsigned int num_utf8_bytes = 0; for (unsigned int j = 0; num_utf8_bytes == 0 && j < 3; j++) { - if ((c & utf8_check_table[j][0]) == utf8_check_table[j][1]) + if ((c & utf8_check_table[j][0]) == utf8_check_table[j][1]) { num_utf8_bytes = j + 2; + } } // get subsequent octets and check that they are valid @@ -1408,11 +1415,14 @@ bool cmFileCopier::Install(const char* fromFile, const char* toFile) if (cmSystemTools::SameFile(fromFile, toFile)) { return true; - } else if (cmSystemTools::FileIsSymlink(fromFile)) { + } + if (cmSystemTools::FileIsSymlink(fromFile)) { return this->InstallSymlink(fromFile, toFile); - } else if (cmSystemTools::FileIsDirectory(fromFile)) { + } + if (cmSystemTools::FileIsDirectory(fromFile)) { return this->InstallDirectory(fromFile, toFile, match_properties); - } else if (cmSystemTools::FileExists(fromFile)) { + } + if (cmSystemTools::FileExists(fromFile)) { return this->InstallFile(fromFile, toFile, match_properties); } return this->ReportMissing(fromFile); @@ -2481,6 +2491,9 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) std::string hashMatchMSG; CM_AUTO_PTR<cmCryptoHash> hash; bool showProgress = false; + std::string userpwd; + + std::list<std::string> curl_headers; while (i != args.end()) { if (*i == "TIMEOUT") { @@ -2564,6 +2577,25 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) return false; } hashMatchMSG = algo + " hash"; + } else if (*i == "USERPWD") { + ++i; + if (i == args.end()) { + this->SetError("DOWNLOAD missing string for USERPWD."); + return false; + } + userpwd = *i; + } else if (*i == "HTTPHEADER") { + ++i; + if (i == args.end()) { + this->SetError("DOWNLOAD missing string for HTTPHEADER."); + return false; + } + curl_headers.push_back(*i); + } else { + // Do not return error for compatibility reason. + std::string err = "Unexpected argument: "; + err += *i; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, err.c_str()); } ++i; } @@ -2698,8 +2730,22 @@ bool cmFileCommand::HandleDownloadCommand(std::vector<std::string> const& args) check_curl_result(res, "DOWNLOAD cannot set progress data: "); } + if (!userpwd.empty()) { + res = ::curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd.c_str()); + check_curl_result(res, "DOWNLOAD cannot set user password: "); + } + + struct curl_slist* headers = CM_NULLPTR; + for (std::list<std::string>::const_iterator h = curl_headers.begin(); + h != curl_headers.end(); ++h) { + headers = ::curl_slist_append(headers, h->c_str()); + } + ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + res = ::curl_easy_perform(curl); + ::curl_slist_free_all(headers); + /* always cleanup */ g_curl.release(); ::curl_easy_cleanup(curl); @@ -2778,6 +2824,9 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) std::string logVar; std::string statusVar; bool showProgress = false; + std::string userpwd; + + std::list<std::string> curl_headers; while (i != args.end()) { if (*i == "TIMEOUT") { @@ -2812,6 +2861,25 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) statusVar = *i; } else if (*i == "SHOW_PROGRESS") { showProgress = true; + } else if (*i == "USERPWD") { + ++i; + if (i == args.end()) { + this->SetError("UPLOAD missing string for USERPWD."); + return false; + } + userpwd = *i; + } else if (*i == "HTTPHEADER") { + ++i; + if (i == args.end()) { + this->SetError("UPLOAD missing string for HTTPHEADER."); + return false; + } + curl_headers.push_back(*i); + } else { + // Do not return error for compatibility reason. + std::string err = "Unexpected argument: "; + err += *i; + this->Makefile->IssueMessage(cmake::AUTHOR_WARNING, err.c_str()); } ++i; @@ -2920,8 +2988,22 @@ bool cmFileCommand::HandleUploadCommand(std::vector<std::string> const& args) ::curl_easy_setopt(curl, CURLOPT_INFILESIZE, static_cast<long>(file_size)); check_curl_result(res, "UPLOAD cannot set input file size: "); + if (!userpwd.empty()) { + res = ::curl_easy_setopt(curl, CURLOPT_USERPWD, userpwd.c_str()); + check_curl_result(res, "UPLOAD cannot set user password: "); + } + + struct curl_slist* headers = CM_NULLPTR; + for (std::list<std::string>::const_iterator h = curl_headers.begin(); + h != curl_headers.end(); ++h) { + headers = ::curl_slist_append(headers, h->c_str()); + } + ::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + res = ::curl_easy_perform(curl); + ::curl_slist_free_all(headers); + /* always cleanup */ g_curl.release(); ::curl_easy_cleanup(curl); @@ -3057,20 +3139,20 @@ bool cmFileCommand::HandleLockCommand(std::vector<std::string> const& args) if (i >= args.size()) { this->Makefile->IssueMessage(cmake::FATAL_ERROR, merr); return false; + } + if (args[i] == "FUNCTION") { + guard = GUARD_FUNCTION; + } else if (args[i] == "FILE") { + guard = GUARD_FILE; + } else if (args[i] == "PROCESS") { + guard = GUARD_PROCESS; } else { - if (args[i] == "FUNCTION") { - guard = GUARD_FUNCTION; - } else if (args[i] == "FILE") { - guard = GUARD_FILE; - } else if (args[i] == "PROCESS") { - guard = GUARD_PROCESS; - } else { - std::ostringstream e; - e << merr << ", but got:\n \"" << args[i] << "\"."; - this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); - return false; - } + std::ostringstream e; + e << merr << ", but got:\n \"" << args[i] << "\"."; + this->Makefile->IssueMessage(cmake::FATAL_ERROR, e.str()); + return false; } + } else if (args[i] == "RESULT_VARIABLE") { ++i; if (i >= args.size()) { @@ -3187,7 +3269,8 @@ bool cmFileCommand::HandleTimestampCommand( if (args.size() < 3) { this->SetError("sub-command TIMESTAMP requires at least two arguments."); return false; - } else if (args.size() > 5) { + } + if (args.size() > 5) { this->SetError("sub-command TIMESTAMP takes at most four arguments."); return false; } diff --git a/Source/cmFileLockUnix.cxx b/Source/cmFileLockUnix.cxx index 6be6abc..64ced9e 100644 --- a/Source/cmFileLockUnix.cxx +++ b/Source/cmFileLockUnix.cxx @@ -37,9 +37,8 @@ cmFileLockResult cmFileLock::Release() if (lockResult == 0) { return cmFileLockResult::MakeOk(); - } else { - return cmFileLockResult::MakeSystem(); } + return cmFileLockResult::MakeSystem(); } cmFileLockResult cmFileLock::OpenFile() @@ -47,18 +46,16 @@ cmFileLockResult cmFileLock::OpenFile() this->File = ::open(this->Filename.c_str(), O_RDWR); if (this->File == -1) { return cmFileLockResult::MakeSystem(); - } else { - return cmFileLockResult::MakeOk(); } + return cmFileLockResult::MakeOk(); } cmFileLockResult cmFileLock::LockWithoutTimeout() { if (this->LockFile(F_SETLKW, F_WRLCK) == -1) { return cmFileLockResult::MakeSystem(); - } else { - return cmFileLockResult::MakeOk(); } + return cmFileLockResult::MakeOk(); } cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds) diff --git a/Source/cmFindBase.cxx b/Source/cmFindBase.cxx index c785e6c..fb95152 100644 --- a/Source/cmFindBase.cxx +++ b/Source/cmFindBase.cxx @@ -321,7 +321,8 @@ bool cmFindBase::CheckForVariableInCache() this->AlreadyInCacheWithoutMetaInfo = true; } return true; - } else if (cached) { + } + if (cached) { const char* hs = state->GetCacheEntryProperty(this->VariableName, "HELPSTRING"); this->VariableDocumentation = hs ? hs : "(none)"; diff --git a/Source/cmFindLibraryCommand.cxx b/Source/cmFindLibraryCommand.cxx index 3094fcf..0fd56b5 100644 --- a/Source/cmFindLibraryCommand.cxx +++ b/Source/cmFindLibraryCommand.cxx @@ -378,9 +378,8 @@ std::string cmFindLibraryCommand::FindNormalLibrary() { if (this->NamesPerDir) { return this->FindNormalLibraryNamesPerDir(); - } else { - return this->FindNormalLibraryDirsPerName(); } + return this->FindNormalLibraryDirsPerName(); } std::string cmFindLibraryCommand::FindNormalLibraryNamesPerDir() @@ -428,9 +427,8 @@ std::string cmFindLibraryCommand::FindFrameworkLibrary() { if (this->NamesPerDir) { return this->FindFrameworkLibraryNamesPerDir(); - } else { - return this->FindFrameworkLibraryDirsPerName(); } + return this->FindFrameworkLibraryDirsPerName(); } std::string cmFindLibraryCommand::FindFrameworkLibraryNamesPerDir() diff --git a/Source/cmFindPackageCommand.cxx b/Source/cmFindPackageCommand.cxx index 8338c2a..8b7bee2 100644 --- a/Source/cmFindPackageCommand.cxx +++ b/Source/cmFindPackageCommand.cxx @@ -12,6 +12,7 @@ #include "cmFindPackageCommand.h" #include "cmAlgorithms.h" +#include <cmSystemTools.h> #include <cmsys/Directory.hxx> #include <cmsys/Encoding.hxx> #include <cmsys/RegularExpression.hxx> @@ -33,6 +34,45 @@ cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::Builds( cmFindPackageCommand::PathLabel cmFindPackageCommand::PathLabel::SystemRegistry("SYSTEM_PACKAGE_REGISTRY"); +struct StrverscmpGreater +{ + bool operator()(const std::string& lhs, const std::string& rhs) const + { + return cmSystemTools::strverscmp(lhs, rhs) > 0; + } +}; + +struct StrverscmpLesser +{ + bool operator()(const std::string& lhs, const std::string& rhs) const + { + return cmSystemTools::strverscmp(lhs, rhs) < 0; + } +}; + +void cmFindPackageCommand::Sort(std::vector<std::string>::iterator begin, + std::vector<std::string>::iterator end, + SortOrderType order, SortDirectionType dir) +{ + if (order == Name_order) { + if (dir == Dec) { + std::sort(begin, end, std::greater<std::string>()); + } else { + std::sort(begin, end); + } + } else if (order == Natural) + // natural order uses letters and numbers (contiguous numbers digit are + // compared such that e.g. 000 00 < 01 < 010 < 09 < 0 < 1 < 9 < 10 + { + if (dir == Dec) { + std::sort(begin, end, StrverscmpGreater()); + } else { + std::sort(begin, end, StrverscmpLesser()); + } + } + // else do not sort +} + cmFindPackageCommand::cmFindPackageCommand() { this->CMakePathName = "PACKAGE"; @@ -58,7 +98,8 @@ cmFindPackageCommand::cmFindPackageCommand() this->VersionFoundTweak = 0; this->VersionFoundCount = 0; this->RequiredCMakeVersion = 0; - + this->SortOrder = None; + this->SortDirection = Asc; this->AppendSearchPathGroups(); } @@ -89,7 +130,7 @@ void cmFindPackageCommand::AppendSearchPathGroups() bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -135,6 +176,23 @@ bool cmFindPackageCommand::InitialPass(std::vector<std::string> const& args, this->NoSystemRegistry = true; } + // Check if Sorting should be enabled + if (const char* so = + this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_ORDER")) { + + if (strcmp(so, "NAME") == 0) { + this->SortOrder = Name_order; + } else if (strcmp(so, "NATURAL") == 0) { + this->SortOrder = Natural; + } else { + this->SortOrder = None; + } + } + if (const char* sd = + this->Makefile->GetDefinition("CMAKE_FIND_PACKAGE_SORT_DIRECTION")) { + this->SortDirection = strcmp(sd, "ASC") == 0 ? Asc : Dec; + } + // Find the current root path mode. this->SelectDefaultRootPathMode(); @@ -1250,18 +1308,16 @@ bool cmFindPackageCommand::CheckPackageRegistryEntry(const std::string& fname, outPaths.AddPath(fname); } return true; - } else { - // The path does not exist. Assume the stream content is - // associated with an old package that no longer exists, and - // delete it to keep the package registry clean. - return false; } - } else { - // The first line in the stream is not the full path to a file or - // directory. Assume the stream content was created by a future - // version of CMake that uses a different format, and leave it. - return true; + // The path does not exist. Assume the stream content is + // associated with an old package that no longer exists, and + // delete it to keep the package registry clean. + return false; } + // The first line in the stream is not the full path to a file or + // directory. Assume the stream content was created by a future + // version of CMake that uses a different format, and leave it. + return true; } void cmFindPackageCommand::FillPrefixesCMakeSystemVariable() @@ -1570,9 +1626,8 @@ private: { if (this->UseSuffixes) { return this->FPC->SearchDirectory(fullPath); - } else { - return this->FPC->CheckDirectory(fullPath); } + return this->FPC->CheckDirectory(fullPath); } cmFindPackageCommand* FPC; bool UseSuffixes; @@ -1595,9 +1650,8 @@ bool cmFileListGeneratorBase::Consider(std::string const& fullPath, { if (this->Next.get()) { return this->Next->Search(fullPath + "/", listing); - } else { - return listing.Visit(fullPath + "/"); } + return listing.Visit(fullPath + "/"); } class cmFileListGeneratorFixed : public cmFileListGeneratorBase @@ -1666,17 +1720,33 @@ private: class cmFileListGeneratorProject : public cmFileListGeneratorBase { public: - cmFileListGeneratorProject(std::vector<std::string> const& names) + cmFileListGeneratorProject(std::vector<std::string> const& names, + cmFindPackageCommand::SortOrderType so, + cmFindPackageCommand::SortDirectionType sd) : cmFileListGeneratorBase() , Names(names) { + this->SetSort(so, sd); } cmFileListGeneratorProject(cmFileListGeneratorProject const& r) : cmFileListGeneratorBase() , Names(r.Names) { + this->SetSort(r.SortOrder, r.SortDirection); + } + + void SetSort(cmFindPackageCommand::SortOrderType o, + cmFindPackageCommand::SortDirectionType d) + { + SortOrder = o; + SortDirection = d; } +protected: + // sort parameters + cmFindPackageCommand::SortOrderType SortOrder; + cmFindPackageCommand::SortDirectionType SortDirection; + private: std::vector<std::string> const& Names; bool Search(std::string const& parent, cmFileList& lister) CM_OVERRIDE @@ -1698,6 +1768,13 @@ private: } } + // before testing the matches check if there is a specific sorting order to + // perform + if (this->SortOrder != cmFindPackageCommand::None) { + cmFindPackageCommand::Sort(matches.begin(), matches.end(), SortOrder, + SortDirection); + } + for (std::vector<std::string>::const_iterator i = matches.begin(); i != matches.end(); ++i) { if (this->Consider(parent + *i, lister)) { @@ -1895,7 +1972,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / - cmFileListGeneratorProject(this->Names); + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection); if (lister.Search()) { return true; } @@ -1905,7 +1983,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorCaseInsensitive("cmake"); if (lister.Search()) { return true; @@ -1932,7 +2011,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) lister / cmFileListGeneratorFixed(prefix) / cmFileListGeneratorEnumerate(common) / cmFileListGeneratorFixed("cmake") / - cmFileListGeneratorProject(this->Names); + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection); if (lister.Search()) { return true; } @@ -1943,7 +2023,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / cmFileListGeneratorEnumerate(common) / - cmFileListGeneratorProject(this->Names); + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection); if (lister.Search()) { return true; } @@ -1954,7 +2035,8 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / cmFileListGeneratorEnumerate(common) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorCaseInsensitive("cmake"); if (lister.Search()) { return true; @@ -1965,10 +2047,12 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorEnumerate(common) / cmFileListGeneratorFixed("cmake") / - cmFileListGeneratorProject(this->Names); + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection); if (lister.Search()) { return true; } @@ -1978,9 +2062,11 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorEnumerate(common) / - cmFileListGeneratorProject(this->Names); + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection); if (lister.Search()) { return true; } @@ -1990,9 +2076,11 @@ bool cmFindPackageCommand::SearchPrefix(std::string const& prefix_in) { cmFindPackageFileList lister(this); lister / cmFileListGeneratorFixed(prefix) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorEnumerate(common) / - cmFileListGeneratorProject(this->Names) / + cmFileListGeneratorProject(this->Names, this->SortOrder, + this->SortDirection) / cmFileListGeneratorCaseInsensitive("cmake"); if (lister.Search()) { return true; diff --git a/Source/cmFindPackageCommand.h b/Source/cmFindPackageCommand.h index 087107e..babdd5a 100644 --- a/Source/cmFindPackageCommand.h +++ b/Source/cmFindPackageCommand.h @@ -24,6 +24,27 @@ class cmFindPackageFileList; class cmFindPackageCommand : public cmFindCommon { public: + /*! A sorting order strategy to be applied to recovered package folders (see + * FIND_PACKAGE_SORT_ORDER)*/ + enum /*class*/ SortOrderType + { + None, + Name_order, + Natural + }; + /*! A sorting direction to be applied to recovered package folders (see + * FIND_PACKAGE_SORT_DIRECTION)*/ + enum /*class*/ SortDirectionType + { + Asc, + Dec + }; + + /*! sorts a given list of string based on the input sort parameters */ + static void Sort(std::vector<std::string>::iterator begin, + std::vector<std::string>::iterator end, SortOrderType order, + SortDirectionType dir); + cmFindPackageCommand(); /** @@ -156,6 +177,11 @@ private: std::vector<std::string> Configs; std::set<std::string> IgnoredPaths; + /*! the selected sortOrder (None by default)*/ + SortOrderType SortOrder; + /*! the selected sortDirection (Asc by default)*/ + SortDirectionType SortDirection; + struct ConfigFileInfo { std::string filename; diff --git a/Source/cmFindPathCommand.cxx b/Source/cmFindPathCommand.cxx index d71fc1a..d8f8795 100644 --- a/Source/cmFindPathCommand.cxx +++ b/Source/cmFindPathCommand.cxx @@ -136,9 +136,8 @@ std::string cmFindPathCommand::FindNormalHeader() if (cmSystemTools::FileExists(tryPath.c_str())) { if (this->IncludeFileInPath) { return tryPath; - } else { - return *p; } + return *p; } } } diff --git a/Source/cmFindProgramCommand.cxx b/Source/cmFindProgramCommand.cxx index 8d142c9..2cdda4c 100644 --- a/Source/cmFindProgramCommand.cxx +++ b/Source/cmFindProgramCommand.cxx @@ -140,9 +140,8 @@ std::string cmFindProgramCommand::FindNormalProgram() { if (this->NamesPerDir) { return this->FindNormalProgramNamesPerDir(); - } else { - return this->FindNormalProgramDirsPerName(); } + return this->FindNormalProgramDirsPerName(); } std::string cmFindProgramCommand::FindNormalProgramNamesPerDir() diff --git a/Source/cmForEachCommand.cxx b/Source/cmForEachCommand.cxx index c6e5f06..4dbbd2c 100644 --- a/Source/cmForEachCommand.cxx +++ b/Source/cmForEachCommand.cxx @@ -81,10 +81,9 @@ bool cmForEachFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, // restore the variable to its prior value mf.AddDefinition(this->Args[0], oldDef.c_str()); return true; - } else { - // close out a nested foreach - this->Depth--; } + // close out a nested foreach + this->Depth--; } // record the command @@ -113,7 +112,7 @@ bool cmForEachFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, bool cmForEachCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmFortranLexer.cxx b/Source/cmFortranLexer.cxx index 7bcd993..60d5591 100644 --- a/Source/cmFortranLexer.cxx +++ b/Source/cmFortranLexer.cxx @@ -347,8 +347,8 @@ static void yynoreturn yy_fatal_error (yyconst char* msg ,yyscan_t yyscanner ); *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 50 -#define YY_END_OF_BUFFER 51 +#define YY_NUM_RULES 54 +#define YY_END_OF_BUFFER 55 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -356,30 +356,31 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[199] = +static yyconst flex_int16_t yy_accept[210] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 51, 45, 47, 46, 49, 1, 45, 33, 2, 35, - 45, 46, 38, 45, 44, 44, 44, 44, 44, 45, - 44, 47, 45, 46, 45, 44, 9, 8, 9, 4, - 3, 45, 0, 10, 0, 0, 0, 0, 0, 33, - 33, 34, 36, 38, 45, 44, 44, 44, 44, 44, - 0, 48, 44, 0, 0, 0, 12, 0, 0, 0, - 0, 0, 0, 45, 0, 11, 44, 0, 0, 5, - 0, 0, 0, 29, 0, 0, 33, 33, 33, 33, - 0, 0, 39, 44, 44, 44, 43, 12, 12, 0, - - 0, 0, 23, 0, 0, 0, 0, 0, 0, 6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 44, - 44, 44, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 30, 31, 0, 0, 0, 0, - 0, 0, 44, 44, 44, 0, 24, 25, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 32, 27, 0, - 0, 20, 0, 44, 44, 42, 0, 26, 21, 0, - 0, 0, 19, 0, 0, 18, 28, 0, 0, 40, - 44, 17, 22, 0, 7, 37, 7, 15, 0, 44, - 14, 16, 41, 0, 0, 0, 13, 0 - + 55, 49, 51, 50, 53, 1, 49, 33, 2, 47, + 48, 35, 37, 50, 39, 49, 46, 46, 46, 46, + 46, 46, 49, 46, 51, 49, 50, 49, 46, 9, + 8, 9, 4, 3, 49, 0, 10, 0, 0, 0, + 0, 0, 33, 33, 34, 36, 39, 49, 46, 46, + 46, 46, 46, 46, 0, 52, 46, 0, 0, 0, + 12, 0, 0, 0, 0, 0, 0, 49, 0, 11, + 46, 0, 0, 5, 0, 0, 0, 29, 0, 0, + 33, 33, 33, 33, 0, 0, 40, 46, 46, 46, + + 46, 45, 12, 12, 0, 0, 0, 23, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 46, 46, 46, 46, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 46, 46, + 46, 46, 0, 24, 25, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 32, 27, 0, 0, 20, 0, + 46, 46, 43, 46, 0, 26, 21, 0, 0, 0, + 19, 0, 0, 18, 28, 0, 0, 41, 46, 46, + 17, 22, 0, 7, 38, 7, 15, 0, 46, 46, + + 14, 16, 42, 44, 0, 0, 0, 13, 0 } ; static yyconst YY_CHAR yy_ec[256] = @@ -387,17 +388,17 @@ static yyconst YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 5, 6, 7, 8, 9, 1, 10, 11, 1, - 1, 12, 1, 13, 1, 1, 1, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 15, 16, 17, - 18, 19, 20, 1, 21, 22, 23, 24, 25, 26, - 22, 22, 27, 22, 22, 28, 29, 30, 31, 22, - 22, 32, 33, 34, 35, 22, 22, 22, 22, 22, - 1, 36, 1, 1, 37, 1, 21, 22, 38, 39, - - 40, 41, 22, 22, 42, 22, 22, 43, 29, 44, - 31, 22, 22, 32, 45, 34, 46, 22, 22, 22, - 22, 22, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 5, 6, 7, 8, 9, 1, 10, 11, 12, + 13, 14, 1, 15, 1, 1, 1, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 17, 18, 19, + 20, 21, 22, 1, 23, 24, 25, 26, 27, 28, + 29, 29, 30, 29, 29, 31, 32, 33, 34, 29, + 29, 35, 36, 37, 38, 29, 29, 29, 29, 29, + 1, 39, 1, 1, 40, 1, 23, 24, 41, 42, + + 43, 44, 29, 29, 45, 29, 29, 46, 32, 47, + 34, 29, 29, 35, 48, 37, 49, 29, 29, 29, + 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -414,211 +415,217 @@ static yyconst YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static yyconst YY_CHAR yy_meta[47] = +static yyconst YY_CHAR yy_meta[50] = { 0, 1, 2, 2, 3, 4, 3, 3, 1, 1, 3, - 3, 1, 3, 5, 1, 3, 1, 3, 6, 1, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 1, 5, 7, 7, 7, - 7, 7, 7, 7, 7, 7 + 3, 3, 3, 1, 3, 5, 3, 3, 1, 3, + 6, 1, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 1, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7 } ; -static yyconst flex_uint16_t yy_base[208] = +static yyconst flex_uint16_t yy_base[219] = { 0, - 0, 45, 0, 46, 392, 53, 49, 59, 61, 71, - 392, 0, 572, 572, 364, 572, 91, 77, 572, 572, - 342, 572, 317, 232, 0, 19, 42, 218, 40, 92, - 137, 96, 174, 240, 220, 257, 572, 238, 97, 572, - 572, 0, 205, 572, 302, 50, 77, 83, 59, 137, - 156, 572, 0, 572, 123, 0, 84, 130, 90, 92, - 167, 572, 0, 176, 347, 0, 190, 94, 175, 200, - 121, 92, 201, 393, 193, 572, 0, 162, 222, 175, - 171, 209, 176, 281, 184, 207, 307, 313, 328, 348, - 338, 111, 0, 205, 213, 125, 0, 354, 185, 280, - - 336, 300, 340, 309, 278, 321, 139, 130, 245, 572, - 335, 347, 351, 356, 360, 375, 375, 379, 383, 300, - 80, 381, 384, 390, 392, 393, 397, 399, 397, 402, - 403, 106, 105, 284, 572, 572, 407, 408, 411, 320, - 413, 413, 420, 419, 421, 420, 572, 572, 421, 426, - 428, 420, 467, 432, 101, 83, 438, 572, 572, 439, - 446, 572, 436, 449, 63, 0, 450, 572, 572, 450, - 453, 481, 572, 64, 0, 572, 572, 454, 460, 0, - 464, 572, 572, 463, 572, 572, 572, 572, 468, 471, - 495, 572, 0, 496, 0, 38, 572, 572, 513, 520, - - 526, 529, 536, 543, 550, 557, 564 + 0, 48, 0, 49, 513, 56, 52, 57, 62, 68, + 515, 0, 583, 583, 509, 583, 97, 74, 583, 583, + 583, 583, 491, 583, 423, 421, 0, 19, 40, 392, + 36, 47, 86, 146, 88, 186, 413, 235, 275, 583, + 407, 98, 583, 583, 0, 386, 583, 323, 65, 73, + 81, 74, 127, 146, 583, 583, 583, 108, 0, 89, + 120, 92, 362, 116, 161, 583, 0, 167, 371, 0, + 168, 131, 146, 171, 81, 89, 352, 420, 353, 583, + 0, 349, 178, 196, 175, 197, 188, 208, 196, 197, + 256, 262, 324, 330, 337, 143, 0, 151, 220, 56, + + 305, 0, 336, 139, 225, 315, 305, 322, 318, 163, + 320, 268, 266, 369, 583, 340, 347, 350, 350, 351, + 357, 350, 357, 363, 140, 235, 359, 218, 362, 375, + 379, 380, 381, 385, 384, 404, 405, 243, 235, 213, + 583, 583, 405, 407, 410, 171, 410, 409, 419, 418, + 423, 426, 311, 583, 583, 428, 429, 431, 173, 462, + 435, 166, 145, 438, 583, 583, 441, 444, 583, 433, + 448, 89, 0, 438, 450, 583, 583, 452, 457, 487, + 583, 114, 0, 583, 583, 457, 462, 0, 465, 463, + 583, 583, 468, 583, 583, 583, 583, 470, 471, 474, + + 500, 583, 0, 0, 505, 0, 65, 583, 583, 524, + 531, 537, 540, 547, 554, 561, 568, 575 } ; -static yyconst flex_int16_t yy_def[208] = +static yyconst flex_int16_t yy_def[219] = { 0, - 198, 1, 1, 1, 1, 1, 199, 199, 199, 199, - 198, 200, 198, 198, 201, 198, 200, 198, 198, 198, - 200, 198, 198, 200, 202, 202, 202, 202, 202, 200, - 202, 198, 198, 198, 203, 198, 198, 198, 198, 198, - 198, 200, 201, 198, 198, 198, 198, 198, 198, 198, - 204, 198, 200, 198, 200, 202, 202, 202, 202, 202, - 198, 198, 31, 198, 198, 65, 200, 198, 198, 198, - 198, 198, 198, 203, 203, 198, 36, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 204, 204, 204, 204, - 198, 198, 202, 202, 202, 202, 202, 198, 198, 198, - - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 202, - 202, 202, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 202, 202, 202, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 202, 202, 202, 198, 198, 198, 198, - 198, 198, 198, 205, 206, 198, 198, 198, 198, 202, - 202, 198, 198, 198, 198, 198, 198, 198, 198, 202, - 198, 198, 202, 198, 207, 207, 198, 0, 198, 198, - - 198, 198, 198, 198, 198, 198, 198 + 209, 1, 1, 1, 1, 1, 210, 210, 210, 210, + 209, 211, 209, 209, 212, 209, 211, 209, 209, 209, + 209, 209, 209, 209, 209, 211, 213, 213, 213, 213, + 213, 213, 211, 213, 209, 209, 209, 214, 209, 209, + 209, 209, 209, 209, 211, 212, 209, 209, 209, 209, + 209, 209, 209, 215, 209, 209, 209, 211, 213, 213, + 213, 213, 213, 213, 209, 209, 34, 209, 209, 69, + 211, 209, 209, 209, 209, 209, 209, 214, 214, 209, + 39, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 215, 215, 215, 215, 209, 209, 213, 213, 213, 213, + + 213, 213, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 213, 213, 213, 213, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 213, 213, + 213, 213, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 213, 213, 213, 213, 209, 209, 209, 209, 209, 209, + 209, 216, 217, 209, 209, 209, 209, 213, 213, 213, + 209, 209, 209, 209, 209, 209, 209, 209, 213, 213, + + 209, 209, 213, 213, 209, 218, 218, 209, 0, 209, + 209, 209, 209, 209, 209, 209, 209, 209 } ; -static yyconst flex_uint16_t yy_nxt[619] = +static yyconst flex_uint16_t yy_nxt[633] = { 0, 12, 13, 14, 13, 13, 15, 16, 12, 17, 18, - 19, 12, 20, 12, 21, 22, 12, 23, 12, 24, - 25, 25, 25, 25, 26, 25, 27, 25, 28, 25, - 25, 25, 25, 25, 29, 30, 31, 25, 25, 26, - 25, 27, 25, 25, 25, 29, 32, 32, 57, 32, - 32, 38, 33, 33, 32, 34, 197, 32, 39, 40, - 33, 38, 57, 38, 35, 186, 186, 41, 39, 40, - 39, 58, 60, 38, 81, 36, 36, 41, 50, 50, - 39, 50, 51, 181, 60, 58, 52, 175, 86, 81, - 36, 36, 45, 61, 62, 45, 61, 64, 79, 80, - - 64, 79, 86, 65, 82, 174, 83, 93, 84, 156, - 155, 144, 85, 96, 46, 47, 97, 48, 100, 82, - 83, 106, 93, 84, 91, 49, 85, 91, 96, 46, - 47, 97, 48, 100, 133, 106, 49, 42, 50, 50, - 119, 50, 51, 132, 42, 42, 52, 105, 42, 92, - 63, 42, 94, 42, 119, 42, 42, 88, 50, 122, - 88, 89, 105, 95, 92, 90, 108, 94, 61, 62, - 122, 61, 42, 63, 42, 66, 109, 64, 66, 109, - 64, 42, 42, 65, 110, 42, 99, 67, 42, 99, - 42, 99, 42, 42, 99, 76, 111, 68, 69, 114, - - 70, 71, 101, 67, 102, 107, 117, 44, 72, 42, - 42, 111, 68, 69, 114, 70, 71, 101, 102, 72, - 74, 117, 76, 79, 80, 103, 79, 74, 74, 104, - 118, 74, 120, 74, 74, 112, 74, 121, 74, 74, - 103, 113, 78, 104, 73, 118, 109, 120, 59, 109, - 112, 55, 121, 113, 110, 74, 74, 75, 75, 76, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 77, 75, 75, 75, 75, 75, 75, 77, 77, 77, - 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 77, 77, 75, 77, 77, 77, 77, 77, 77, 77, - - 77, 77, 77, 45, 115, 123, 45, 130, 88, 50, - 116, 88, 89, 157, 88, 50, 90, 88, 89, 115, - 123, 130, 90, 126, 116, 46, 47, 157, 48, 88, - 50, 129, 88, 89, 143, 54, 49, 90, 126, 91, - 46, 47, 91, 48, 131, 143, 129, 49, 66, 88, - 50, 66, 88, 89, 161, 99, 53, 90, 99, 131, - 98, 134, 124, 127, 92, 161, 44, 98, 125, 128, - 68, 69, 135, 70, 71, 136, 134, 124, 127, 92, - 125, 72, 137, 128, 138, 68, 69, 135, 70, 71, - 136, 198, 72, 74, 34, 76, 198, 137, 139, 138, - - 74, 74, 140, 141, 74, 142, 74, 74, 145, 74, - 146, 74, 74, 139, 198, 147, 148, 140, 141, 149, - 142, 150, 151, 145, 152, 146, 153, 154, 74, 74, - 147, 148, 158, 159, 149, 160, 150, 151, 162, 152, - 163, 153, 154, 164, 165, 166, 168, 158, 159, 167, - 160, 169, 170, 162, 171, 163, 198, 173, 164, 165, - 166, 168, 176, 167, 177, 171, 169, 170, 172, 178, - 179, 172, 173, 180, 182, 183, 184, 176, 188, 177, - 98, 179, 172, 189, 178, 172, 190, 191, 180, 182, - 183, 184, 192, 188, 98, 193, 194, 194, 189, 194, - - 194, 190, 191, 198, 198, 198, 198, 192, 198, 198, - 193, 195, 195, 37, 37, 37, 37, 37, 37, 37, - 42, 198, 198, 198, 42, 42, 43, 43, 43, 43, - 43, 43, 43, 56, 198, 56, 75, 75, 75, 75, - 75, 75, 75, 87, 87, 87, 87, 87, 87, 87, - 185, 185, 185, 198, 185, 185, 185, 187, 198, 187, - 198, 187, 187, 187, 196, 196, 196, 196, 196, 198, - 196, 11, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198 + 19, 20, 21, 12, 22, 12, 23, 24, 12, 25, + 12, 26, 27, 27, 27, 27, 28, 27, 27, 29, + 27, 30, 27, 27, 27, 31, 27, 32, 33, 34, + 27, 27, 28, 27, 29, 27, 27, 31, 32, 35, + 35, 60, 35, 35, 41, 36, 36, 35, 37, 41, + 35, 42, 43, 36, 41, 60, 42, 43, 44, 38, + 41, 42, 61, 63, 44, 53, 53, 42, 53, 54, + 39, 39, 64, 55, 63, 208, 61, 65, 66, 68, + 65, 85, 68, 127, 64, 69, 39, 39, 48, 83, + + 84, 48, 83, 86, 127, 87, 90, 85, 88, 95, + 110, 189, 95, 89, 97, 195, 195, 100, 86, 87, + 90, 111, 49, 50, 88, 110, 51, 89, 53, 53, + 97, 53, 54, 100, 52, 111, 55, 96, 49, 50, + 104, 51, 102, 104, 98, 52, 45, 92, 53, 183, + 92, 93, 96, 45, 45, 94, 99, 105, 102, 45, + 98, 67, 65, 66, 45, 65, 45, 45, 68, 104, + 182, 68, 104, 105, 69, 124, 106, 149, 107, 83, + 84, 125, 83, 71, 45, 67, 45, 70, 149, 124, + 70, 106, 107, 45, 45, 136, 125, 114, 108, 45, + + 114, 71, 116, 109, 45, 115, 45, 45, 168, 136, + 179, 72, 73, 119, 108, 74, 75, 109, 116, 168, + 122, 179, 123, 76, 45, 45, 117, 72, 73, 119, + 74, 75, 118, 120, 76, 78, 122, 80, 123, 163, + 121, 117, 78, 78, 118, 164, 126, 162, 78, 120, + 78, 152, 129, 78, 121, 78, 78, 92, 53, 164, + 92, 93, 126, 92, 53, 94, 92, 93, 129, 150, + 139, 94, 138, 78, 78, 79, 79, 80, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 81, 79, 79, 79, 79, 79, 79, 81, 81, 81, + + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 79, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 48, 92, 53, 48, 92, 93, + 132, 92, 53, 94, 92, 93, 128, 104, 95, 94, + 104, 95, 135, 175, 130, 137, 132, 133, 49, 50, + 131, 103, 51, 113, 134, 80, 112, 175, 135, 130, + 52, 137, 131, 133, 49, 50, 96, 51, 134, 140, + 114, 52, 70, 114, 141, 70, 142, 144, 115, 143, + 146, 96, 145, 147, 140, 101, 103, 148, 47, 151, + 141, 153, 142, 144, 143, 146, 72, 73, 145, 147, + + 74, 75, 154, 148, 151, 155, 153, 157, 76, 156, + 158, 82, 72, 73, 159, 74, 75, 77, 154, 76, + 78, 155, 80, 157, 156, 62, 158, 78, 78, 159, + 160, 161, 165, 78, 166, 78, 167, 169, 78, 170, + 78, 78, 58, 57, 171, 172, 160, 161, 165, 173, + 166, 174, 167, 169, 170, 176, 177, 178, 78, 78, + 171, 172, 181, 180, 184, 173, 180, 174, 185, 186, + 187, 176, 177, 178, 188, 190, 191, 103, 181, 192, + 184, 187, 193, 197, 185, 186, 190, 198, 180, 199, + 188, 180, 191, 200, 201, 192, 202, 203, 193, 197, + + 204, 205, 103, 198, 205, 199, 205, 56, 200, 205, + 201, 47, 202, 203, 209, 37, 204, 209, 206, 209, + 209, 209, 209, 206, 40, 40, 40, 40, 40, 40, + 40, 45, 209, 209, 209, 45, 45, 46, 46, 46, + 46, 46, 46, 46, 59, 209, 59, 79, 79, 79, + 79, 79, 79, 79, 91, 91, 91, 91, 91, 91, + 91, 194, 194, 194, 209, 194, 194, 194, 196, 209, + 196, 209, 196, 196, 196, 207, 207, 207, 207, 207, + 209, 207, 11, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209 } ; -static yyconst flex_int16_t yy_chk[619] = +static yyconst flex_int16_t yy_chk[633] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 4, 26, 2, - 4, 7, 2, 4, 6, 6, 196, 6, 7, 7, - 6, 8, 26, 9, 6, 174, 174, 9, 8, 8, - 9, 27, 29, 10, 46, 6, 6, 10, 18, 18, - 10, 18, 18, 165, 29, 27, 18, 156, 49, 46, - 6, 6, 17, 30, 30, 17, 30, 32, 39, 39, - - 32, 39, 49, 32, 47, 155, 47, 57, 48, 133, - 132, 121, 48, 59, 17, 17, 60, 17, 68, 47, - 47, 72, 57, 48, 55, 17, 48, 55, 59, 17, - 17, 60, 17, 68, 108, 72, 17, 31, 50, 50, - 92, 50, 50, 107, 31, 31, 50, 71, 31, 55, - 31, 31, 58, 31, 92, 31, 31, 51, 51, 96, - 51, 51, 71, 58, 55, 51, 78, 58, 61, 61, - 96, 61, 31, 31, 33, 33, 80, 64, 33, 80, - 64, 33, 33, 64, 80, 33, 99, 33, 33, 99, - 33, 67, 33, 33, 67, 75, 81, 33, 33, 83, - - 33, 33, 69, 67, 69, 73, 85, 43, 33, 33, - 33, 81, 33, 33, 83, 33, 33, 69, 69, 33, - 35, 85, 35, 79, 79, 70, 79, 35, 35, 70, - 86, 35, 94, 35, 35, 82, 35, 95, 35, 35, - 70, 82, 38, 70, 34, 86, 109, 94, 28, 109, - 82, 24, 95, 82, 109, 35, 35, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - - 36, 36, 36, 45, 84, 100, 45, 105, 87, 87, - 84, 87, 87, 134, 88, 88, 87, 88, 88, 84, - 100, 105, 88, 102, 84, 45, 45, 134, 45, 89, - 89, 104, 89, 89, 120, 23, 45, 89, 102, 91, - 45, 45, 91, 45, 106, 120, 104, 45, 65, 90, - 90, 65, 90, 90, 140, 98, 21, 90, 98, 106, - 65, 111, 101, 103, 91, 140, 15, 98, 101, 103, - 65, 65, 112, 65, 65, 113, 111, 101, 103, 91, - 101, 65, 114, 103, 115, 65, 65, 112, 65, 65, - 113, 11, 65, 74, 5, 74, 0, 114, 116, 115, - - 74, 74, 117, 118, 74, 119, 74, 74, 122, 74, - 123, 74, 74, 116, 0, 124, 125, 117, 118, 126, - 119, 127, 128, 122, 129, 123, 130, 131, 74, 74, - 124, 125, 137, 138, 126, 139, 127, 128, 141, 129, - 142, 130, 131, 143, 144, 145, 149, 137, 138, 146, - 139, 150, 151, 141, 152, 142, 0, 154, 143, 144, - 145, 149, 157, 146, 160, 152, 150, 151, 153, 161, - 163, 153, 154, 164, 167, 170, 171, 157, 178, 160, - 153, 163, 172, 179, 161, 172, 181, 184, 164, 167, - 170, 171, 189, 178, 172, 190, 191, 194, 179, 191, - - 194, 181, 184, 0, 0, 0, 0, 189, 0, 0, - 190, 191, 194, 199, 199, 199, 199, 199, 199, 199, - 200, 0, 0, 0, 200, 200, 201, 201, 201, 201, - 201, 201, 201, 202, 0, 202, 203, 203, 203, 203, - 203, 203, 203, 204, 204, 204, 204, 204, 204, 204, - 205, 205, 205, 0, 205, 205, 205, 206, 0, 206, - 0, 206, 206, 206, 207, 207, 207, 207, 207, 0, - 207, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - - 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, - 198, 198, 198, 198, 198, 198, 198, 198 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 4, 28, 2, 4, 7, 2, 4, 6, 6, 8, + 6, 7, 7, 6, 9, 28, 8, 8, 9, 6, + 10, 9, 29, 31, 10, 18, 18, 10, 18, 18, + 6, 6, 32, 18, 31, 207, 29, 33, 33, 35, + 33, 49, 35, 100, 32, 35, 6, 6, 17, 42, + + 42, 17, 42, 50, 100, 50, 52, 49, 51, 58, + 75, 172, 58, 51, 60, 182, 182, 62, 50, 50, + 52, 76, 17, 17, 51, 75, 17, 51, 53, 53, + 60, 53, 53, 62, 17, 76, 53, 58, 17, 17, + 104, 17, 64, 104, 61, 17, 34, 54, 54, 163, + 54, 54, 58, 34, 34, 54, 61, 72, 64, 34, + 61, 34, 65, 65, 34, 65, 34, 34, 68, 71, + 162, 68, 71, 72, 68, 96, 73, 125, 73, 83, + 83, 98, 83, 71, 34, 34, 36, 36, 125, 96, + 36, 73, 73, 36, 36, 110, 98, 84, 74, 36, + + 84, 36, 85, 74, 36, 84, 36, 36, 146, 110, + 159, 36, 36, 87, 74, 36, 36, 74, 85, 146, + 89, 159, 90, 36, 36, 36, 86, 36, 36, 87, + 36, 36, 86, 88, 36, 38, 89, 38, 90, 139, + 88, 86, 38, 38, 86, 140, 99, 138, 38, 88, + 38, 128, 105, 38, 88, 38, 38, 91, 91, 140, + 91, 91, 99, 92, 92, 91, 92, 92, 105, 126, + 113, 92, 112, 38, 38, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 48, 93, 93, 48, 93, 93, + 107, 94, 94, 93, 94, 94, 101, 103, 95, 94, + 103, 95, 109, 153, 106, 111, 107, 108, 48, 48, + 106, 103, 48, 82, 108, 79, 77, 153, 109, 106, + 48, 111, 106, 108, 48, 48, 95, 48, 108, 116, + 114, 48, 69, 114, 117, 69, 118, 120, 114, 119, + 122, 95, 121, 123, 116, 63, 69, 124, 46, 127, + 117, 129, 118, 120, 119, 122, 69, 69, 121, 123, + + 69, 69, 130, 124, 127, 131, 129, 133, 69, 132, + 134, 41, 69, 69, 135, 69, 69, 37, 130, 69, + 78, 131, 78, 133, 132, 30, 134, 78, 78, 135, + 136, 137, 143, 78, 144, 78, 145, 147, 78, 148, + 78, 78, 26, 25, 149, 150, 136, 137, 143, 151, + 144, 152, 145, 147, 148, 156, 157, 158, 78, 78, + 149, 150, 161, 160, 164, 151, 160, 152, 167, 168, + 170, 156, 157, 158, 171, 174, 175, 160, 161, 178, + 164, 170, 179, 186, 167, 168, 174, 187, 180, 189, + 171, 180, 175, 190, 193, 178, 198, 199, 179, 186, + + 200, 201, 180, 187, 201, 189, 205, 23, 190, 205, + 193, 15, 198, 199, 11, 5, 200, 0, 201, 0, + 0, 0, 0, 205, 210, 210, 210, 210, 210, 210, + 210, 211, 0, 0, 0, 211, 211, 212, 212, 212, + 212, 212, 212, 212, 213, 0, 213, 214, 214, 214, + 214, 214, 214, 214, 215, 215, 215, 215, 215, 215, + 215, 216, 216, 216, 0, 216, 216, 216, 217, 0, + 217, 0, 217, 217, 217, 218, 218, 218, 218, 218, + 0, 218, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209 } ; /* The intent behind this definition is that it'll catch @@ -685,7 +692,7 @@ Modify cmFortranLexer.cxx: /*--------------------------------------------------------------------------*/ -#line 689 "cmFortranLexer.cxx" +#line 696 "cmFortranLexer.cxx" #define INITIAL 0 #define free_fmt 1 @@ -956,7 +963,7 @@ YY_DECL #line 65 "cmFortranLexer.in.l" -#line 960 "cmFortranLexer.cxx" +#line 967 "cmFortranLexer.cxx" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -984,13 +991,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 199 ) + if ( yy_current_state >= 210 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 572 ); + while ( yy_base[yy_current_state] != 583 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -1201,71 +1208,87 @@ YY_RULE_SETUP #line 148 "cmFortranLexer.in.l" { return DCOLON; } case 37: -/* rule 37 can match eol */ YY_RULE_SETUP -#line 150 "cmFortranLexer.in.l" -{ return GARBAGE; } +#line 149 "cmFortranLexer.in.l" +{ return COLON; } case 38: +/* rule 38 can match eol */ YY_RULE_SETUP -#line 152 "cmFortranLexer.in.l" -{ return ASSIGNMENT_OP; } +#line 151 "cmFortranLexer.in.l" +{ return GARBAGE; } case 39: YY_RULE_SETUP -#line 154 "cmFortranLexer.in.l" -{ return END; } +#line 153 "cmFortranLexer.in.l" +{ return ASSIGNMENT_OP; } case 40: YY_RULE_SETUP #line 155 "cmFortranLexer.in.l" -{ return INCLUDE; } +{ return END; } case 41: YY_RULE_SETUP #line 156 "cmFortranLexer.in.l" -{ return INTERFACE; } +{ return INCLUDE; } case 42: YY_RULE_SETUP #line 157 "cmFortranLexer.in.l" -{ return MODULE; } +{ return INTERFACE; } case 43: YY_RULE_SETUP #line 158 "cmFortranLexer.in.l" -{ return USE; } +{ return MODULE; } case 44: YY_RULE_SETUP +#line 159 "cmFortranLexer.in.l" +{ return SUBMODULE; } +case 45: +YY_RULE_SETUP #line 160 "cmFortranLexer.in.l" +{ return USE; } +case 46: +YY_RULE_SETUP +#line 162 "cmFortranLexer.in.l" { yylvalp->string = strdup(yytext); return WORD; } -case 45: +case 47: +YY_RULE_SETUP +#line 167 "cmFortranLexer.in.l" +{ return LPAREN; } +case 48: +YY_RULE_SETUP +#line 168 "cmFortranLexer.in.l" +{ return RPAREN; } +case 49: YY_RULE_SETUP -#line 165 "cmFortranLexer.in.l" +#line 170 "cmFortranLexer.in.l" { return GARBAGE; } -case 46: -/* rule 46 can match eol */ +case 50: +/* rule 50 can match eol */ YY_RULE_SETUP -#line 167 "cmFortranLexer.in.l" +#line 172 "cmFortranLexer.in.l" { return EOSTMT; } -case 47: +case 51: YY_RULE_SETUP -#line 170 "cmFortranLexer.in.l" +#line 175 "cmFortranLexer.in.l" /* Ignore */ YY_BREAK -case 48: -/* rule 48 can match eol */ +case 52: +/* rule 52 can match eol */ YY_RULE_SETUP -#line 171 "cmFortranLexer.in.l" +#line 176 "cmFortranLexer.in.l" /* Ignore line-endings preceded by \ */ YY_BREAK -case 49: +case 53: YY_RULE_SETUP -#line 173 "cmFortranLexer.in.l" +#line 178 "cmFortranLexer.in.l" { return *yytext; } case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(free_fmt): case YY_STATE_EOF(fixed_fmt): case YY_STATE_EOF(str_sq): case YY_STATE_EOF(str_dq): -#line 175 "cmFortranLexer.in.l" +#line 180 "cmFortranLexer.in.l" { if(!cmFortranParser_FilePop(yyextra) ) { @@ -1273,12 +1296,12 @@ case YY_STATE_EOF(str_dq): } } YY_BREAK -case 50: +case 54: YY_RULE_SETUP -#line 182 "cmFortranLexer.in.l" +#line 187 "cmFortranLexer.in.l" ECHO; YY_BREAK -#line 1320 "cmFortranLexer.cxx" +#line 1347 "cmFortranLexer.cxx" case YY_END_OF_BUFFER: { @@ -1572,7 +1595,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 199 ) + if ( yy_current_state >= 210 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; @@ -1601,11 +1624,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 199 ) + if ( yy_current_state >= 210 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (flex_int16_t) yy_c]; - yy_is_jam = (yy_current_state == 198); + yy_is_jam = (yy_current_state == 209); (void)yyg; return yy_is_jam ? 0 : yy_current_state; @@ -2447,7 +2470,7 @@ void cmFortran_yyfree (void * ptr , yyscan_t yyscanner) #define YYTABLES_NAME "yytables" -#line 182 "cmFortranLexer.in.l" +#line 187 "cmFortranLexer.in.l" diff --git a/Source/cmFortranLexer.h b/Source/cmFortranLexer.h index cb175ec..851f37f 100644 --- a/Source/cmFortranLexer.h +++ b/Source/cmFortranLexer.h @@ -337,7 +337,7 @@ extern int cmFortran_yylex (yyscan_t yyscanner); #undef YY_DECL #endif -#line 182 "cmFortranLexer.in.l" +#line 187 "cmFortranLexer.in.l" #line 344 "cmFortranLexer.h" diff --git a/Source/cmFortranLexer.in.l b/Source/cmFortranLexer.in.l index 6870f7c..ea3c132 100644 --- a/Source/cmFortranLexer.in.l +++ b/Source/cmFortranLexer.in.l @@ -146,6 +146,7 @@ $[ \t]*endif { return F90PPR_ENDIF; } , { return COMMA; } :: { return DCOLON; } +: { return COLON; } <fixed_fmt>\n[ ]{5}[^ ] { return GARBAGE; } @@ -155,6 +156,7 @@ $[ \t]*endif { return F90PPR_ENDIF; } [Ii][Nn][Cc][Ll][Uu][Dd][Ee] { return INCLUDE; } [Ii][Nn][Tt][Ee][Rr][Ff][Aa][Cc][Ee] { return INTERFACE; } [Mm][Oo][Dd][Uu][Ll][Ee] { return MODULE; } +[Ss][Uu][bb][Mm][Oo][Dd][Uu][Ll][Ee] { return SUBMODULE; } [Uu][Ss][Ee] { return USE; } [a-zA-Z_][a-zA-Z_0-9]* { @@ -162,7 +164,10 @@ $[ \t]*endif { return F90PPR_ENDIF; } return WORD; } -[^ \t\n\r;,!'"a-zA-Z=&]+ { return GARBAGE; } +\( { return LPAREN; } +\) { return RPAREN; } + +[^ \t\n\r:;,!'"a-zA-Z=&()]+ { return GARBAGE; } ;|\n { return EOSTMT; } diff --git a/Source/cmFortranParser.cxx b/Source/cmFortranParser.cxx index bf4e7c4..2b3e22d 100644 --- a/Source/cmFortranParser.cxx +++ b/Source/cmFortranParser.cxx @@ -192,16 +192,20 @@ extern int cmFortran_yydebug; F90PPR_ELIF = 279, F90PPR_ENDIF = 280, COMMA = 281, - DCOLON = 282, - UNTERMINATED_STRING = 283, - STRING = 284, - WORD = 285, - CPP_INCLUDE_ANGLE = 286, - END = 287, - INCLUDE = 288, - INTERFACE = 289, - MODULE = 290, - USE = 291 + COLON = 282, + DCOLON = 283, + LPAREN = 284, + RPAREN = 285, + UNTERMINATED_STRING = 286, + STRING = 287, + WORD = 288, + CPP_INCLUDE_ANGLE = 289, + END = 290, + INCLUDE = 291, + INTERFACE = 292, + MODULE = 293, + SUBMODULE = 294, + USE = 295 }; #endif /* Tokens. */ @@ -229,16 +233,20 @@ extern int cmFortran_yydebug; #define F90PPR_ELIF 279 #define F90PPR_ENDIF 280 #define COMMA 281 -#define DCOLON 282 -#define UNTERMINATED_STRING 283 -#define STRING 284 -#define WORD 285 -#define CPP_INCLUDE_ANGLE 286 -#define END 287 -#define INCLUDE 288 -#define INTERFACE 289 -#define MODULE 290 -#define USE 291 +#define COLON 282 +#define DCOLON 283 +#define LPAREN 284 +#define RPAREN 285 +#define UNTERMINATED_STRING 286 +#define STRING 287 +#define WORD 288 +#define CPP_INCLUDE_ANGLE 289 +#define END 290 +#define INCLUDE 291 +#define INTERFACE 292 +#define MODULE 293 +#define SUBMODULE 294 +#define USE 295 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED @@ -249,7 +257,7 @@ union YYSTYPE char* string; -#line 253 "cmFortranParser.cxx" /* yacc.c:355 */ +#line 261 "cmFortranParser.cxx" /* yacc.c:355 */ }; typedef union YYSTYPE YYSTYPE; @@ -265,7 +273,7 @@ int cmFortran_yyparse (yyscan_t yyscanner); /* Copy the second part of user declarations. */ -#line 269 "cmFortranParser.cxx" /* yacc.c:358 */ +#line 277 "cmFortranParser.cxx" /* yacc.c:358 */ #ifdef short # undef short @@ -507,21 +515,21 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 469 +#define YYLAST 593 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 37 +#define YYNTOKENS 41 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 14 /* YYNRULES -- Number of rules. */ -#define YYNRULES 57 +#define YYNRULES 63 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 109 +#define YYNSTATES 126 /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 291 +#define YYMAXUTOK 295 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -559,19 +567,20 @@ static const yytype_uint8 yytranslate[] = 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36 + 35, 36, 37, 38, 39, 40 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 102, 102, 102, 105, 109, 114, 119, 124, 128, - 133, 141, 146, 151, 156, 161, 166, 171, 176, 181, - 185, 189, 193, 197, 198, 203, 203, 203, 204, 204, - 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, - 210, 210, 211, 211, 212, 212, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226 + 0, 103, 103, 103, 106, 110, 115, 124, 130, 137, + 142, 146, 151, 159, 164, 169, 174, 179, 184, 189, + 194, 199, 203, 207, 211, 215, 216, 221, 221, 221, + 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, + 227, 227, 228, 228, 229, 229, 230, 230, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248 }; #endif @@ -585,10 +594,11 @@ static const char *const yytname[] = "F90PPR_DEFINE", "CPP_DEFINE", "F90PPR_UNDEF", "CPP_UNDEF", "CPP_IFDEF", "CPP_IFNDEF", "CPP_IF", "CPP_ELSE", "CPP_ELIF", "CPP_ENDIF", "F90PPR_IFDEF", "F90PPR_IFNDEF", "F90PPR_IF", "F90PPR_ELSE", - "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA", "DCOLON", "UNTERMINATED_STRING", - "STRING", "WORD", "CPP_INCLUDE_ANGLE", "END", "INCLUDE", "INTERFACE", - "MODULE", "USE", "$accept", "code", "stmt", "include", "define", "undef", - "ifdef", "ifndef", "if", "elif", "else", "endif", "other", "misc_code", YY_NULLPTR + "F90PPR_ELIF", "F90PPR_ENDIF", "COMMA", "COLON", "DCOLON", "LPAREN", + "RPAREN", "UNTERMINATED_STRING", "STRING", "WORD", "CPP_INCLUDE_ANGLE", + "END", "INCLUDE", "INTERFACE", "MODULE", "SUBMODULE", "USE", "$accept", + "code", "stmt", "include", "define", "undef", "ifdef", "ifndef", "if", + "elif", "else", "endif", "other", "misc_code", YY_NULLPTR }; #endif @@ -600,14 +610,15 @@ static const yytype_uint16 yytoknum[] = 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291 + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295 }; # endif -#define YYPACT_NINF -38 +#define YYPACT_NINF -39 #define yypact_value_is_default(Yystate) \ - (!!((Yystate) == (-38))) + (!!((Yystate) == (-39))) #define YYTABLE_NINF -1 @@ -618,17 +629,19 @@ static const yytype_uint16 yytoknum[] = STATE-NUM. */ static const yytype_int16 yypact[] = { - -38, 39, -38, 3, -38, -20, -38, -38, -38, -38, - -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -38, -38, -38, -38, -38, -22, -16, 1, -8, - -6, -38, -4, -7, -3, -2, -1, -38, -38, -38, - -38, -38, -38, 62, -38, -38, -38, -38, -38, 0, - 2, -38, -38, -38, -38, -38, -38, 73, 107, 118, - 152, 163, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -38, -38, -38, -38, -38, 197, 208, 242, 253, - 6, -38, 287, 298, 332, 343, 377, 388, -38, -38, - -38, -38, -38, -38, -38, -38, -38, 4, 422, -38, - -38, -38, -38, -38, -38, -38, -38, 433, -38 + -39, 21, -39, 1, -39, -20, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -24, -18, 20, -8, + -3, 39, -39, 15, 16, 18, 19, 33, -39, -39, + -39, -39, -39, -39, 59, -39, -39, -39, -39, -39, + 35, 36, 37, -39, -39, -39, -39, -39, -39, 76, + 114, 129, 167, 182, -39, -39, -39, -39, -39, -39, + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, 220, 235, 273, 288, -21, 26, -39, 326, + 341, 379, 394, 432, 447, -39, -39, -39, -39, -39, + -39, -39, -39, -39, 38, 40, 41, 485, -39, -39, + -39, -39, -39, -39, 45, -39, -39, -39, 43, 500, + 538, -39, -39, -39, 553, -39 }; /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. @@ -636,31 +649,33 @@ static const yytype_int16 yypact[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 2, 0, 1, 0, 23, 0, 25, 26, 27, 29, - 28, 31, 30, 32, 34, 36, 40, 38, 42, 33, - 35, 37, 41, 39, 43, 44, 0, 0, 0, 0, - 0, 3, 0, 0, 0, 0, 0, 44, 44, 44, - 44, 24, 44, 0, 44, 44, 4, 44, 44, 0, - 0, 44, 44, 44, 44, 44, 44, 0, 0, 0, - 0, 0, 13, 54, 53, 56, 55, 57, 52, 46, - 47, 48, 49, 50, 51, 45, 0, 0, 0, 0, - 0, 44, 0, 0, 0, 0, 0, 0, 19, 20, - 21, 22, 12, 8, 11, 7, 6, 0, 0, 5, - 14, 15, 16, 17, 18, 44, 9, 0, 10 + 2, 0, 1, 0, 25, 0, 27, 28, 29, 31, + 30, 33, 32, 34, 36, 38, 42, 40, 44, 35, + 37, 39, 43, 41, 45, 46, 0, 0, 0, 0, + 0, 0, 3, 0, 0, 0, 0, 0, 46, 46, + 46, 46, 26, 46, 0, 46, 46, 4, 46, 46, + 0, 0, 0, 46, 46, 46, 46, 46, 46, 0, + 0, 0, 0, 0, 15, 57, 56, 62, 58, 59, + 60, 61, 63, 55, 48, 49, 50, 51, 52, 53, + 54, 47, 0, 0, 0, 0, 0, 0, 46, 0, + 0, 0, 0, 0, 0, 21, 22, 23, 24, 14, + 10, 13, 9, 6, 0, 0, 0, 0, 5, 16, + 17, 18, 19, 20, 0, 46, 46, 11, 0, 0, + 0, 46, 7, 12, 0, 8 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int8 yypgoto[] = { - -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -38, -37, -38 + -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, + -39, -39, -38, -39 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int8 yydefgoto[] = { - -1, 1, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 43, 75 + -1, 1, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 44, 81 }; /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If @@ -668,143 +683,173 @@ static const yytype_int8 yydefgoto[] = number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_uint8 yytable[] = { - 57, 58, 59, 60, 46, 61, 41, 76, 77, 42, - 78, 79, 44, 45, 82, 83, 84, 85, 86, 87, - 49, 50, 48, 53, 51, 52, 0, 54, 55, 56, - 80, 47, 81, 97, 105, 0, 0, 0, 0, 2, - 3, 0, 4, 0, 98, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 62, 63, 64, 107, 0, - 25, 26, 27, 28, 29, 30, 88, 63, 64, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 69, 0, 70, 71, 72, 73, 74, 65, - 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, - 89, 63, 64, 0, 0, 0, 0, 0, 0, 0, - 0, 90, 63, 64, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 65, 66, 67, 68, 69, 0, 70, - 71, 72, 73, 74, 65, 66, 67, 68, 69, 0, - 70, 71, 72, 73, 74, 91, 63, 64, 0, 0, - 0, 0, 0, 0, 0, 0, 92, 63, 64, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 69, 0, 70, 71, 72, 73, 74, 65, - 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, - 93, 63, 64, 0, 0, 0, 0, 0, 0, 0, - 0, 94, 63, 64, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 65, 66, 67, 68, 69, 0, 70, - 71, 72, 73, 74, 65, 66, 67, 68, 69, 0, - 70, 71, 72, 73, 74, 95, 63, 64, 0, 0, - 0, 0, 0, 0, 0, 0, 96, 63, 64, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 69, 0, 70, 71, 72, 73, 74, 65, - 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, - 99, 63, 64, 0, 0, 0, 0, 0, 0, 0, - 0, 100, 63, 64, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 65, 66, 67, 68, 69, 0, 70, - 71, 72, 73, 74, 65, 66, 67, 68, 69, 0, - 70, 71, 72, 73, 74, 101, 63, 64, 0, 0, - 0, 0, 0, 0, 0, 0, 102, 63, 64, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 69, 0, 70, 71, 72, 73, 74, 65, - 66, 67, 68, 69, 0, 70, 71, 72, 73, 74, - 103, 63, 64, 0, 0, 0, 0, 0, 0, 0, - 0, 104, 63, 64, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 65, 66, 67, 68, 69, 0, 70, - 71, 72, 73, 74, 65, 66, 67, 68, 69, 0, - 70, 71, 72, 73, 74, 106, 63, 64, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 63, 64, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, - 67, 68, 69, 0, 70, 71, 72, 73, 74, 65, - 66, 67, 68, 69, 0, 70, 71, 72, 73, 74 + 59, 60, 61, 62, 42, 63, 104, 82, 83, 105, + 84, 85, 43, 45, 46, 89, 90, 91, 92, 93, + 94, 2, 3, 47, 4, 49, 50, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 54, 0, 55, + 107, 56, 57, 48, 106, 25, 26, 27, 28, 29, + 30, 31, 64, 65, 66, 51, 58, 52, 86, 87, + 88, 114, 53, 115, 116, 118, 121, 119, 120, 95, + 65, 66, 0, 124, 0, 67, 68, 69, 70, 71, + 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, + 0, 0, 67, 68, 69, 70, 71, 72, 73, 74, + 0, 75, 76, 77, 78, 79, 80, 96, 65, 66, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 97, 65, 66, 0, 0, 0, 0, 0, + 67, 68, 69, 70, 71, 72, 73, 74, 0, 75, + 76, 77, 78, 79, 80, 67, 68, 69, 70, 71, + 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, + 98, 65, 66, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 99, 65, 66, 0, 0, + 0, 0, 0, 67, 68, 69, 70, 71, 72, 73, + 74, 0, 75, 76, 77, 78, 79, 80, 67, 68, + 69, 70, 71, 72, 73, 74, 0, 75, 76, 77, + 78, 79, 80, 100, 65, 66, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 101, 65, + 66, 0, 0, 0, 0, 0, 67, 68, 69, 70, + 71, 72, 73, 74, 0, 75, 76, 77, 78, 79, + 80, 67, 68, 69, 70, 71, 72, 73, 74, 0, + 75, 76, 77, 78, 79, 80, 102, 65, 66, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 103, 65, 66, 0, 0, 0, 0, 0, 67, + 68, 69, 70, 71, 72, 73, 74, 0, 75, 76, + 77, 78, 79, 80, 67, 68, 69, 70, 71, 72, + 73, 74, 0, 75, 76, 77, 78, 79, 80, 108, + 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 65, 66, 0, 0, 0, + 0, 0, 67, 68, 69, 70, 71, 72, 73, 74, + 0, 75, 76, 77, 78, 79, 80, 67, 68, 69, + 70, 71, 72, 73, 74, 0, 75, 76, 77, 78, + 79, 80, 110, 65, 66, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 111, 65, 66, + 0, 0, 0, 0, 0, 67, 68, 69, 70, 71, + 72, 73, 74, 0, 75, 76, 77, 78, 79, 80, + 67, 68, 69, 70, 71, 72, 73, 74, 0, 75, + 76, 77, 78, 79, 80, 112, 65, 66, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 113, 65, 66, 0, 0, 0, 0, 0, 67, 68, + 69, 70, 71, 72, 73, 74, 0, 75, 76, 77, + 78, 79, 80, 67, 68, 69, 70, 71, 72, 73, + 74, 0, 75, 76, 77, 78, 79, 80, 117, 65, + 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 122, 65, 66, 0, 0, 0, 0, + 0, 67, 68, 69, 70, 71, 72, 73, 74, 0, + 75, 76, 77, 78, 79, 80, 67, 68, 69, 70, + 71, 72, 73, 74, 0, 75, 76, 77, 78, 79, + 80, 123, 65, 66, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 125, 65, 66, 0, + 0, 0, 0, 0, 67, 68, 69, 70, 71, 72, + 73, 74, 0, 75, 76, 77, 78, 79, 80, 67, + 68, 69, 70, 71, 72, 73, 74, 0, 75, 76, + 77, 78, 79, 80 }; static const yytype_int8 yycheck[] = { - 37, 38, 39, 40, 3, 42, 3, 44, 45, 29, - 47, 48, 34, 29, 51, 52, 53, 54, 55, 56, - 26, 27, 30, 30, 30, 29, -1, 30, 30, 30, - 30, 30, 30, 27, 30, -1, -1, -1, -1, 0, - 1, -1, 3, -1, 81, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 3, 4, 5, 105, -1, - 31, 32, 33, 34, 35, 36, 3, 4, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, 26, - 27, 28, 29, 30, -1, 32, 33, 34, 35, 36, - 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 26, 27, 28, 29, 30, -1, 32, - 33, 34, 35, 36, 26, 27, 28, 29, 30, -1, - 32, 33, 34, 35, 36, 3, 4, 5, -1, -1, - -1, -1, -1, -1, -1, -1, 3, 4, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, 26, - 27, 28, 29, 30, -1, 32, 33, 34, 35, 36, - 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 26, 27, 28, 29, 30, -1, 32, - 33, 34, 35, 36, 26, 27, 28, 29, 30, -1, - 32, 33, 34, 35, 36, 3, 4, 5, -1, -1, - -1, -1, -1, -1, -1, -1, 3, 4, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, 26, - 27, 28, 29, 30, -1, 32, 33, 34, 35, 36, + 38, 39, 40, 41, 3, 43, 27, 45, 46, 30, + 48, 49, 32, 37, 32, 53, 54, 55, 56, 57, + 58, 0, 1, 3, 3, 33, 29, 6, 7, 8, + 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 23, 24, 25, 32, -1, 33, + 88, 33, 33, 33, 28, 34, 35, 36, 37, 38, + 39, 40, 3, 4, 5, 26, 33, 28, 33, 33, + 33, 33, 33, 33, 33, 30, 33, 115, 116, 3, + 4, 5, -1, 121, -1, 26, 27, 28, 29, 30, + 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, + -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, + -1, 35, 36, 37, 38, 39, 40, 3, 4, 5, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3, 4, 5, -1, -1, -1, -1, -1, + 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, + 36, 37, 38, 39, 40, 26, 27, 28, 29, 30, + 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 26, 27, 28, 29, 30, -1, 32, - 33, 34, 35, 36, 26, 27, 28, 29, 30, -1, - 32, 33, 34, 35, 36, 3, 4, 5, -1, -1, + -1, -1, -1, -1, -1, 3, 4, 5, -1, -1, + -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, + 33, -1, 35, 36, 37, 38, 39, 40, 26, 27, + 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, + 38, 39, 40, 3, 4, 5, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, + 5, -1, -1, -1, -1, -1, 26, 27, 28, 29, + 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, + 40, 26, 27, 28, 29, 30, 31, 32, 33, -1, + 35, 36, 37, 38, 39, 40, 3, 4, 5, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3, 4, 5, -1, -1, -1, -1, -1, 26, + 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, + 37, 38, 39, 40, 26, 27, 28, 29, 30, 31, + 32, 33, -1, 35, 36, 37, 38, 39, 40, 3, + 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 3, 4, 5, -1, -1, -1, + -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, + -1, 35, 36, 37, 38, 39, 40, 26, 27, 28, + 29, 30, 31, 32, 33, -1, 35, 36, 37, 38, + 39, 40, 3, 4, 5, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, + -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, + 31, 32, 33, -1, 35, 36, 37, 38, 39, 40, + 26, 27, 28, 29, 30, 31, 32, 33, -1, 35, + 36, 37, 38, 39, 40, 3, 4, 5, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 3, 4, 5, -1, -1, -1, -1, -1, 26, 27, + 28, 29, 30, 31, 32, 33, -1, 35, 36, 37, + 38, 39, 40, 26, 27, 28, 29, 30, 31, 32, + 33, -1, 35, 36, 37, 38, 39, 40, 3, 4, + 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3, 4, 5, -1, -1, -1, -1, + -1, 26, 27, 28, 29, 30, 31, 32, 33, -1, + 35, 36, 37, 38, 39, 40, 26, 27, 28, 29, + 30, 31, 32, 33, -1, 35, 36, 37, 38, 39, + 40, 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 3, 4, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, 26, - 27, 28, 29, 30, -1, 32, 33, 34, 35, 36, - 3, 4, 5, -1, -1, -1, -1, -1, -1, -1, - -1, 3, 4, 5, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 26, 27, 28, 29, 30, -1, 32, - 33, 34, 35, 36, 26, 27, 28, 29, 30, -1, - 32, 33, 34, 35, 36, 3, 4, 5, -1, -1, - -1, -1, -1, -1, -1, -1, 3, 4, 5, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 26, 27, - 28, 29, 30, -1, 32, 33, 34, 35, 36, 26, - 27, 28, 29, 30, -1, 32, 33, 34, 35, 36 + -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, + 32, 33, -1, 35, 36, 37, 38, 39, 40, 26, + 27, 28, 29, 30, 31, 32, 33, -1, 35, 36, + 37, 38, 39, 40 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 38, 0, 1, 3, 6, 7, 8, 9, 10, + 0, 42, 0, 1, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 31, 32, 33, 34, 35, - 36, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 3, 29, 49, 34, 29, 3, 30, 30, 26, - 27, 30, 29, 30, 30, 30, 30, 49, 49, 49, - 49, 49, 3, 4, 5, 26, 27, 28, 29, 30, - 32, 33, 34, 35, 36, 50, 49, 49, 49, 49, - 30, 30, 49, 49, 49, 49, 49, 49, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 27, 49, 3, - 3, 3, 3, 3, 3, 30, 3, 49, 3 + 21, 22, 23, 24, 25, 34, 35, 36, 37, 38, + 39, 40, 43, 44, 45, 46, 47, 48, 49, 50, + 51, 52, 3, 32, 53, 37, 32, 3, 33, 33, + 29, 26, 28, 33, 32, 33, 33, 33, 33, 53, + 53, 53, 53, 53, 3, 4, 5, 26, 27, 28, + 29, 30, 31, 32, 33, 35, 36, 37, 38, 39, + 40, 54, 53, 53, 53, 53, 33, 33, 33, 53, + 53, 53, 53, 53, 53, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 27, 30, 28, 53, 3, 3, + 3, 3, 3, 3, 33, 33, 33, 3, 30, 53, + 53, 33, 3, 3, 53, 3 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 37, 38, 38, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 40, 40, 40, 41, 41, - 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, - 47, 47, 48, 48, 49, 49, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50 + 0, 41, 42, 42, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, + 45, 45, 46, 46, 47, 47, 48, 48, 49, 49, + 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ static const yytype_uint8 yyr2[] = { - 0, 2, 0, 2, 2, 4, 4, 4, 4, 5, - 7, 4, 4, 3, 4, 4, 4, 4, 4, 3, - 3, 3, 3, 1, 2, 1, 1, 1, 1, 1, + 0, 2, 0, 2, 2, 4, 4, 7, 9, 4, + 4, 5, 7, 4, 4, 3, 4, 4, 4, 4, + 4, 3, 3, 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 + 1, 1, 1, 1, 1, 1, 0, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1 }; @@ -1487,65 +1532,92 @@ yyreduce: switch (yyn) { case 4: -#line 105 "cmFortranParser.y" /* yacc.c:1646 */ +#line 106 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); } -#line 1496 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1541 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 5: -#line 109 "cmFortranParser.y" /* yacc.c:1646 */ +#line 110 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1506 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1551 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 6: -#line 114 "cmFortranParser.y" /* yacc.c:1646 */ +#line 115 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); - cmFortranParser_RuleModule(parser, (yyvsp[-2].string)); + if (cmsysString_strcasecmp((yyvsp[-2].string), "function") != 0 && + cmsysString_strcasecmp((yyvsp[-2].string), "procedure") != 0 && + cmsysString_strcasecmp((yyvsp[-2].string), "subroutine") != 0) { + cmFortranParser_RuleModule(parser, (yyvsp[-2].string)); + } free((yyvsp[-2].string)); } -#line 1516 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1565 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 7: -#line 119 "cmFortranParser.y" /* yacc.c:1646 */ +#line 124 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); - cmFortranParser_SetInInterface(parser, true); + cmFortranParser_RuleUse(parser, (yyvsp[-4].string)); + free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1526 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1576 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 8: -#line 124 "cmFortranParser.y" /* yacc.c:1646 */ +#line 130 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); - cmFortranParser_SetInInterface(parser, false); + cmFortranParser_RuleUse(parser, (yyvsp[-6].string)); + free((yyvsp[-6].string)); + free((yyvsp[-4].string)); + free((yyvsp[-2].string)); } -#line 1535 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1588 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 9: -#line 128 "cmFortranParser.y" /* yacc.c:1646 */ +#line 137 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); - cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); + cmFortranParser_SetInInterface(parser, true); free((yyvsp[-2].string)); } -#line 1545 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1598 "cmFortranParser.cxx" /* yacc.c:1646 */ break; case 10: -#line 133 "cmFortranParser.y" /* yacc.c:1646 */ +#line 142 "cmFortranParser.y" /* yacc.c:1646 */ + { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_SetInInterface(parser, false); + } +#line 1607 "cmFortranParser.cxx" /* yacc.c:1646 */ + break; + + case 11: +#line 146 "cmFortranParser.y" /* yacc.c:1646 */ + { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_RuleUse(parser, (yyvsp[-2].string)); + free((yyvsp[-2].string)); + } +#line 1617 "cmFortranParser.cxx" /* yacc.c:1646 */ + break; + + case 12: +#line 151 "cmFortranParser.y" /* yacc.c:1646 */ { if (cmsysString_strcasecmp((yyvsp[-4].string), "non_intrinsic") == 0) { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); @@ -1554,139 +1626,139 @@ yyreduce: free((yyvsp[-4].string)); free((yyvsp[-2].string)); } -#line 1558 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1630 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 11: -#line 141 "cmFortranParser.y" /* yacc.c:1646 */ + case 13: +#line 159 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1568 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1640 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 12: -#line 146 "cmFortranParser.y" /* yacc.c:1646 */ + case 14: +#line 164 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleLineDirective(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1578 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1650 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 13: -#line 151 "cmFortranParser.y" /* yacc.c:1646 */ + case 15: +#line 169 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1588 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1660 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 14: -#line 156 "cmFortranParser.y" /* yacc.c:1646 */ + case 16: +#line 174 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleInclude(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1598 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1670 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 15: -#line 161 "cmFortranParser.y" /* yacc.c:1646 */ + case 17: +#line 179 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleDefine(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1608 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1680 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 16: -#line 166 "cmFortranParser.y" /* yacc.c:1646 */ + case 18: +#line 184 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleUndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1618 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1690 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 17: -#line 171 "cmFortranParser.y" /* yacc.c:1646 */ + case 19: +#line 189 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfdef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1628 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1700 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 18: -#line 176 "cmFortranParser.y" /* yacc.c:1646 */ + case 20: +#line 194 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIfndef(parser, (yyvsp[-2].string)); free((yyvsp[-2].string)); } -#line 1638 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1710 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 19: -#line 181 "cmFortranParser.y" /* yacc.c:1646 */ + case 21: +#line 199 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleIf(parser); } -#line 1647 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1719 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 20: -#line 185 "cmFortranParser.y" /* yacc.c:1646 */ + case 22: +#line 203 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElif(parser); } -#line 1656 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1728 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 21: -#line 189 "cmFortranParser.y" /* yacc.c:1646 */ + case 23: +#line 207 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleElse(parser); } -#line 1665 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1737 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 22: -#line 193 "cmFortranParser.y" /* yacc.c:1646 */ + case 24: +#line 211 "cmFortranParser.y" /* yacc.c:1646 */ { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_RuleEndif(parser); } -#line 1674 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1746 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 46: -#line 215 "cmFortranParser.y" /* yacc.c:1646 */ + case 48: +#line 233 "cmFortranParser.y" /* yacc.c:1646 */ { free ((yyvsp[0].string)); } -#line 1680 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1752 "cmFortranParser.cxx" /* yacc.c:1646 */ break; - case 52: -#line 221 "cmFortranParser.y" /* yacc.c:1646 */ + case 55: +#line 240 "cmFortranParser.y" /* yacc.c:1646 */ { free ((yyvsp[0].string)); } -#line 1686 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1758 "cmFortranParser.cxx" /* yacc.c:1646 */ break; -#line 1690 "cmFortranParser.cxx" /* yacc.c:1646 */ +#line 1762 "cmFortranParser.cxx" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1916,6 +1988,6 @@ yyreturn: #endif return yyresult; } -#line 229 "cmFortranParser.y" /* yacc.c:1906 */ +#line 251 "cmFortranParser.y" /* yacc.c:1906 */ /* End of grammar */ diff --git a/Source/cmFortranParser.y b/Source/cmFortranParser.y index b856a1a..d3327e9 100644 --- a/Source/cmFortranParser.y +++ b/Source/cmFortranParser.y @@ -85,7 +85,7 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message) %token CPP_IFDEF CPP_IFNDEF CPP_IF CPP_ELSE CPP_ELIF CPP_ENDIF %token F90PPR_IFDEF F90PPR_IFNDEF F90PPR_IF %token F90PPR_ELSE F90PPR_ELIF F90PPR_ENDIF -%token COMMA DCOLON +%token COMMA COLON DCOLON LPAREN RPAREN %token <number> UNTERMINATED_STRING %token <string> STRING WORD %token <string> CPP_INCLUDE_ANGLE @@ -93,6 +93,7 @@ static void cmFortran_yyerror(yyscan_t yyscanner, const char* message) %token INCLUDE %token INTERFACE %token MODULE +%token SUBMODULE %token USE /*-------------------------------------------------------------------------*/ @@ -113,9 +114,26 @@ stmt: } | MODULE WORD other EOSTMT { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); - cmFortranParser_RuleModule(parser, $2); + if (cmsysString_strcasecmp($2, "function") != 0 && + cmsysString_strcasecmp($2, "procedure") != 0 && + cmsysString_strcasecmp($2, "subroutine") != 0) { + cmFortranParser_RuleModule(parser, $2); + } free($2); } +| SUBMODULE LPAREN WORD RPAREN WORD other EOSTMT { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_RuleUse(parser, $3); + free($3); + free($5); + } +| SUBMODULE LPAREN WORD COLON WORD RPAREN WORD other EOSTMT { + cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); + cmFortranParser_RuleUse(parser, $3); + free($3); + free($5); + free($7); + } | INTERFACE WORD other EOSTMT { cmFortranParser* parser = cmFortran_yyget_extra(yyscanner); cmFortranParser_SetInInterface(parser, true); @@ -217,11 +235,15 @@ misc_code: | INCLUDE | INTERFACE | MODULE +| SUBMODULE | USE | STRING { free ($1); } | GARBAGE | ASSIGNMENT_OP +| COLON | DCOLON +| LPAREN +| RPAREN | COMMA | UNTERMINATED_STRING ; diff --git a/Source/cmFortranParserTokens.h b/Source/cmFortranParserTokens.h index e988df4..18b9e0a 100644 --- a/Source/cmFortranParserTokens.h +++ b/Source/cmFortranParserTokens.h @@ -69,16 +69,20 @@ extern int cmFortran_yydebug; F90PPR_ELIF = 279, F90PPR_ENDIF = 280, COMMA = 281, - DCOLON = 282, - UNTERMINATED_STRING = 283, - STRING = 284, - WORD = 285, - CPP_INCLUDE_ANGLE = 286, - END = 287, - INCLUDE = 288, - INTERFACE = 289, - MODULE = 290, - USE = 291 + COLON = 282, + DCOLON = 283, + LPAREN = 284, + RPAREN = 285, + UNTERMINATED_STRING = 286, + STRING = 287, + WORD = 288, + CPP_INCLUDE_ANGLE = 289, + END = 290, + INCLUDE = 291, + INTERFACE = 292, + MODULE = 293, + SUBMODULE = 294, + USE = 295 }; #endif /* Tokens. */ @@ -106,16 +110,20 @@ extern int cmFortran_yydebug; #define F90PPR_ELIF 279 #define F90PPR_ENDIF 280 #define COMMA 281 -#define DCOLON 282 -#define UNTERMINATED_STRING 283 -#define STRING 284 -#define WORD 285 -#define CPP_INCLUDE_ANGLE 286 -#define END 287 -#define INCLUDE 288 -#define INTERFACE 289 -#define MODULE 290 -#define USE 291 +#define COLON 282 +#define DCOLON 283 +#define LPAREN 284 +#define RPAREN 285 +#define UNTERMINATED_STRING 286 +#define STRING 287 +#define WORD 288 +#define CPP_INCLUDE_ANGLE 289 +#define END 290 +#define INCLUDE 291 +#define INTERFACE 292 +#define MODULE 293 +#define SUBMODULE 294 +#define USE 295 /* Value type. */ #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED @@ -126,7 +134,7 @@ union YYSTYPE char* string; -#line 130 "cmFortranParserTokens.h" /* yacc.c:1909 */ +#line 138 "cmFortranParserTokens.h" /* yacc.c:1909 */ }; typedef union YYSTYPE YYSTYPE; diff --git a/Source/cmFunctionCommand.cxx b/Source/cmFunctionCommand.cxx index 40c54db..8aa1b77 100644 --- a/Source/cmFunctionCommand.cxx +++ b/Source/cmFunctionCommand.cxx @@ -169,10 +169,9 @@ bool cmFunctionFunctionBlocker::IsFunctionBlocked( // remove the function blocker now that the function is defined mf.RemoveFunctionBlocker(this, lff); return true; - } else { - // decrement for each nested function that ends - this->Depth--; } + // decrement for each nested function that ends + this->Depth--; } // if it wasn't an endfunction and we are not executing then we must be @@ -202,7 +201,7 @@ bool cmFunctionFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, bool cmFunctionCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 7dd8e7f..f181cf6 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -1162,7 +1162,28 @@ bool cmGeneratorTarget::NeedRelinkBeforeInstall( // If either a build or install tree rpath is set then the rpath // will likely change between the build tree and install tree and // this target must be relinked. - return this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(); + bool have_rpath = + this->HaveBuildTreeRPATH(config) || this->HaveInstallTreeRPATH(); + bool is_ninja = + this->LocalGenerator->GetGlobalGenerator()->GetName() == "Ninja"; + + if (have_rpath && is_ninja) { + std::ostringstream w; + /* clang-format off */ + w << + "The install of the " << this->GetName() << " target requires " + "changing an RPATH from the build tree, but this is not supported " + "with the Ninja generator unless on an ELF-based platform. The " + "CMAKE_BUILD_WITH_INSTALL_RPATH variable may be set to avoid this " + "relinking step." + ; + /* clang-format on */ + + cmake* cm = this->LocalGenerator->GetCMakeInstance(); + cm->IssueMessage(cmake::FATAL_ERROR, w.str(), this->GetBacktrace()); + } + + return have_rpath; } bool cmGeneratorTarget::IsChrpathUsed(const std::string& config) const @@ -1280,11 +1301,11 @@ bool cmGeneratorTarget::HasMacOSXRpathInstallNameDir( if (!this->Makefile->IsSet("CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG")) { std::ostringstream w; - w << "Attempting to use"; + w << "Attempting to use "; if (macosx_rpath) { - w << " MACOSX_RPATH"; + w << "MACOSX_RPATH"; } else { - w << " @rpath"; + w << "@rpath"; } w << " without CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG being set."; w << " This could be because you are using a Mac OS X version"; @@ -3862,23 +3883,35 @@ void cmGeneratorTarget::GetTargetVersion(bool soversion, int& major, } } -std::string cmGeneratorTarget::GetFortranModuleDirectory() const +std::string cmGeneratorTarget::GetFortranModuleDirectory( + std::string const& working_dir) const { if (!this->FortranModuleDirectoryCreated) { this->FortranModuleDirectory = true; - this->FortranModuleDirectory = this->CreateFortranModuleDirectory(); + this->FortranModuleDirectory = + this->CreateFortranModuleDirectory(working_dir); } return this->FortranModuleDirectory; } -std::string cmGeneratorTarget::CreateFortranModuleDirectory() const +std::string cmGeneratorTarget::CreateFortranModuleDirectory( + std::string const& working_dir) const { std::string mod_dir; - const char* target_mod_dir = this->GetProperty("Fortran_MODULE_DIRECTORY"); + std::string target_mod_dir; + if (const char* prop = this->GetProperty("Fortran_MODULE_DIRECTORY")) { + target_mod_dir = prop; + } else { + std::string const& default_mod_dir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + if (default_mod_dir != working_dir) { + target_mod_dir = default_mod_dir; + } + } const char* moddir_flag = this->Makefile->GetDefinition("CMAKE_Fortran_MODDIR_FLAG"); - if (target_mod_dir && moddir_flag) { + if (!target_mod_dir.empty() && moddir_flag) { // Compute the full path to the module directory. if (cmSystemTools::FileIsFullPath(target_mod_dir)) { // Already a full path. diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 715220e..8e17b8f 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -537,12 +537,13 @@ public: void GetTargetVersion(bool soversion, int& major, int& minor, int& patch) const; - std::string GetFortranModuleDirectory() const; + std::string GetFortranModuleDirectory(std::string const& working_dir) const; private: void AddSourceCommon(const std::string& src); - std::string CreateFortranModuleDirectory() const; + std::string CreateFortranModuleDirectory( + std::string const& working_dir) const; mutable bool FortranModuleDirectoryCreated; mutable std::string FortranModuleDirectory; diff --git a/Source/cmGetPropertyCommand.cxx b/Source/cmGetPropertyCommand.cxx index 2307e08..8063328 100644 --- a/Source/cmGetPropertyCommand.cxx +++ b/Source/cmGetPropertyCommand.cxx @@ -252,19 +252,17 @@ bool cmGetPropertyCommand::HandleTargetMode() if (this->PropertyName == "ALIASED_TARGET") { if (this->Makefile->IsAlias(this->Name)) { return this->StoreResult(target->GetName().c_str()); - } else { - return this->StoreResult(NULL); } + return this->StoreResult(CM_NULLPTR); } return this->StoreResult( target->GetProperty(this->PropertyName, this->Makefile)); - } else { - std::ostringstream e; - e << "could not find TARGET " << this->Name - << ". Perhaps it has not yet been created."; - this->SetError(e.str()); - return false; } + std::ostringstream e; + e << "could not find TARGET " << this->Name + << ". Perhaps it has not yet been created."; + this->SetError(e.str()); + return false; } bool cmGetPropertyCommand::HandleSourceMode() @@ -277,13 +275,11 @@ bool cmGetPropertyCommand::HandleSourceMode() // Get the source file. if (cmSourceFile* sf = this->Makefile->GetOrCreateSource(this->Name)) { return this->StoreResult(sf->GetPropertyForUser(this->PropertyName)); - } else { - std::ostringstream e; - e << "given SOURCE name that could not be found or created: " - << this->Name; - this->SetError(e.str()); - return false; } + std::ostringstream e; + e << "given SOURCE name that could not be found or created: " << this->Name; + this->SetError(e.str()); + return false; } bool cmGetPropertyCommand::HandleTestMode() @@ -347,11 +343,9 @@ bool cmGetPropertyCommand::HandleInstallMode() bool isSet = file->GetProperty(this->PropertyName, value); return this->StoreResult(isSet ? value.c_str() : CM_NULLPTR); - } else { - std::ostringstream e; - e << "given INSTALL name that could not be found or created: " - << this->Name; - this->SetError(e.str()); - return false; } + std::ostringstream e; + e << "given INSTALL name that could not be found or created: " << this->Name; + this->SetError(e.str()); + return false; } diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index ef8266f..4772474 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -94,6 +94,7 @@ cmGlobalGenerator::cmGlobalGenerator(cmake* cm) this->TryCompileOuterMakefile = CM_NULLPTR; this->ConfigureDoneCMP0026AndCMP0024 = false; + this->FirstTimeProgress = 0.0f; cm->GetState()->SetMinGWMake(false); cm->GetState()->SetMSYSShell(false); @@ -1060,16 +1061,16 @@ void cmGlobalGenerator::Configure() this->ConfigureDoneCMP0026AndCMP0024 = true; // Put a copy of each global target in every directory. - cmTargets globalTargets; - this->CreateDefaultGlobalTargets(&globalTargets); + std::vector<GlobalTargetInfo> globalTargets; + this->CreateDefaultGlobalTargets(globalTargets); for (unsigned int i = 0; i < this->Makefiles.size(); ++i) { cmMakefile* mf = this->Makefiles[i]; cmTargets* targets = &(mf->GetTargets()); - cmTargets::iterator tit; - for (tit = globalTargets.begin(); tit != globalTargets.end(); ++tit) { - (*targets)[tit->first] = tit->second; - (*targets)[tit->first].SetMakefile(mf); + for (std::vector<GlobalTargetInfo>::iterator gti = globalTargets.begin(); + gti != globalTargets.end(); ++gti) { + targets->insert( + cmTargets::value_type(gti->Name, this->CreateGlobalTarget(*gti, mf))); } } @@ -2069,15 +2070,27 @@ inline std::string removeQuotes(const std::string& s) return s; } -void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) +void cmGlobalGenerator::CreateDefaultGlobalTargets( + std::vector<GlobalTargetInfo>& targets) +{ + this->AddGlobalTarget_Package(targets); + this->AddGlobalTarget_PackageSource(targets); + this->AddGlobalTarget_Test(targets); + this->AddGlobalTarget_EditCache(targets); + this->AddGlobalTarget_RebuildCache(targets); + this->AddGlobalTarget_Install(targets); +} + +void cmGlobalGenerator::AddGlobalTarget_Package( + std::vector<GlobalTargetInfo>& targets) { cmMakefile* mf = this->Makefiles[0]; const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); - - // CPack - std::string workingDir = mf->GetCurrentBinaryDirectory(); - cmCustomCommandLines cpackCommandLines; - std::vector<std::string> depends; + GlobalTargetInfo gti; + gti.Name = this->GetPackageTargetName(); + gti.Message = "Run CPack packaging tool..."; + gti.UsesTerminal = true; + gti.WorkingDir = mf->GetCurrentBinaryDirectory(); cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCPackCommand()); if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { @@ -2086,55 +2099,61 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) } singleLine.push_back("--config"); std::string configFile = mf->GetCurrentBinaryDirectory(); - ; configFile += "/CPackConfig.cmake"; std::string relConfigFile = "./CPackConfig.cmake"; singleLine.push_back(relConfigFile); - cpackCommandLines.push_back(singleLine); + gti.CommandLines.push_back(singleLine); if (this->GetPreinstallTargetName()) { - depends.push_back(this->GetPreinstallTargetName()); + gti.Depends.push_back(this->GetPreinstallTargetName()); } else { const char* noPackageAll = mf->GetDefinition("CMAKE_SKIP_PACKAGE_ALL_DEPENDENCY"); if (!noPackageAll || cmSystemTools::IsOff(noPackageAll)) { - depends.push_back(this->GetAllTargetName()); + gti.Depends.push_back(this->GetAllTargetName()); } } if (cmSystemTools::FileExists(configFile.c_str())) { - (*targets)[this->GetPackageTargetName()] = this->CreateGlobalTarget( - this->GetPackageTargetName(), "Run CPack packaging tool...", - &cpackCommandLines, depends, workingDir.c_str(), /*uses_terminal*/ true); + targets.push_back(gti); } - // CPack source +} + +void cmGlobalGenerator::AddGlobalTarget_PackageSource( + std::vector<GlobalTargetInfo>& targets) +{ + cmMakefile* mf = this->Makefiles[0]; const char* packageSourceTargetName = this->GetPackageSourceTargetName(); if (packageSourceTargetName) { - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - singleLine.erase(singleLine.begin(), singleLine.end()); - depends.erase(depends.begin(), depends.end()); + GlobalTargetInfo gti; + gti.Name = packageSourceTargetName; + gti.Message = "Run CPack packaging tool for source..."; + gti.WorkingDir = mf->GetCurrentBinaryDirectory(); + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCPackCommand()); singleLine.push_back("--config"); - configFile = mf->GetCurrentBinaryDirectory(); - ; + std::string configFile = mf->GetCurrentBinaryDirectory(); configFile += "/CPackSourceConfig.cmake"; - relConfigFile = "./CPackSourceConfig.cmake"; + std::string relConfigFile = "./CPackSourceConfig.cmake"; singleLine.push_back(relConfigFile); if (cmSystemTools::FileExists(configFile.c_str())) { singleLine.push_back(configFile); - cpackCommandLines.push_back(singleLine); - (*targets)[packageSourceTargetName] = this->CreateGlobalTarget( - packageSourceTargetName, "Run CPack packaging tool for source...", - &cpackCommandLines, depends, workingDir.c_str(), - /*uses_terminal*/ true); + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); } } +} - // Test +void cmGlobalGenerator::AddGlobalTarget_Test( + std::vector<GlobalTargetInfo>& targets) +{ + cmMakefile* mf = this->Makefiles[0]; + const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); if (mf->IsOn("CMAKE_TESTING_ENABLED")) { - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - singleLine.erase(singleLine.begin(), singleLine.end()); - depends.erase(depends.begin(), depends.end()); + GlobalTargetInfo gti; + gti.Name = this->GetTestTargetName(); + gti.Message = "Running tests..."; + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCTestCommand()); singleLine.push_back("--force-new-ctest-process"); if (cmakeCfgIntDir && *cmakeCfgIntDir && cmakeCfgIntDir[0] != '.') { @@ -2145,20 +2164,19 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) { singleLine.push_back("$(ARGS)"); } - cpackCommandLines.push_back(singleLine); - (*targets)[this->GetTestTargetName()] = - this->CreateGlobalTarget(this->GetTestTargetName(), "Running tests...", - &cpackCommandLines, depends, CM_NULLPTR, - /*uses_terminal*/ true); + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); } +} - // Edit Cache +void cmGlobalGenerator::AddGlobalTarget_EditCache( + std::vector<GlobalTargetInfo>& targets) +{ const char* editCacheTargetName = this->GetEditCacheTargetName(); if (editCacheTargetName) { - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - singleLine.erase(singleLine.begin(), singleLine.end()); - depends.erase(depends.begin(), depends.end()); + GlobalTargetInfo gti; + gti.Name = editCacheTargetName; + cmCustomCommandLine singleLine; // Use generator preference for the edit_cache rule if it is defined. std::string edit_cmd = this->GetEditCacheCommand(); @@ -2166,39 +2184,46 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) singleLine.push_back(edit_cmd); singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); - cpackCommandLines.push_back(singleLine); - (*targets)[editCacheTargetName] = this->CreateGlobalTarget( - editCacheTargetName, "Running CMake cache editor...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true); + gti.Message = "Running CMake cache editor..."; + gti.UsesTerminal = true; + gti.CommandLines.push_back(singleLine); } else { singleLine.push_back(cmSystemTools::GetCMakeCommand()); singleLine.push_back("-E"); singleLine.push_back("echo"); singleLine.push_back("No interactive CMake dialog available."); - cpackCommandLines.push_back(singleLine); - (*targets)[editCacheTargetName] = this->CreateGlobalTarget( - editCacheTargetName, "No interactive CMake dialog available...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ false); + gti.Message = "No interactive CMake dialog available..."; + gti.UsesTerminal = false; + gti.CommandLines.push_back(singleLine); } + + targets.push_back(gti); } +} - // Rebuild Cache +void cmGlobalGenerator::AddGlobalTarget_RebuildCache( + std::vector<GlobalTargetInfo>& targets) +{ const char* rebuildCacheTargetName = this->GetRebuildCacheTargetName(); if (rebuildCacheTargetName) { - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - singleLine.erase(singleLine.begin(), singleLine.end()); - depends.erase(depends.begin(), depends.end()); + GlobalTargetInfo gti; + gti.Name = rebuildCacheTargetName; + gti.Message = "Running CMake to regenerate build system..."; + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; singleLine.push_back(cmSystemTools::GetCMakeCommand()); singleLine.push_back("-H$(CMAKE_SOURCE_DIR)"); singleLine.push_back("-B$(CMAKE_BINARY_DIR)"); - cpackCommandLines.push_back(singleLine); - (*targets)[rebuildCacheTargetName] = this->CreateGlobalTarget( - rebuildCacheTargetName, "Running CMake to regenerate build system...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true); + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); } +} - // Install +void cmGlobalGenerator::AddGlobalTarget_Install( + std::vector<GlobalTargetInfo>& targets) +{ + cmMakefile* mf = this->Makefiles[0]; + const char* cmakeCfgIntDir = this->GetCMakeCFGIntDir(); bool skipInstallRules = mf->IsOn("CMAKE_SKIP_INSTALL_RULES"); if (this->InstallTargetEnabled && skipInstallRules) { this->CMakeInstance->IssueMessage( @@ -2208,9 +2233,6 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) } else if (this->InstallTargetEnabled && !skipInstallRules) { if (!cmakeCfgIntDir || !*cmakeCfgIntDir || cmakeCfgIntDir[0] == '.') { std::set<std::string>* componentsSet = &this->InstallComponents; - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - depends.erase(depends.begin(), depends.end()); std::ostringstream ostr; if (!componentsSet->empty()) { ostr << "Available install components are: "; @@ -2218,23 +2240,25 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) } else { ostr << "Only default component available"; } - singleLine.push_back(ostr.str()); - (*targets)["list_install_components"] = this->CreateGlobalTarget( - "list_install_components", ostr.str().c_str(), &cpackCommandLines, - depends, CM_NULLPTR, /*uses_terminal*/ false); + GlobalTargetInfo gti; + gti.Name = "list_install_components"; + gti.Message = ostr.str(); + gti.UsesTerminal = false; + targets.push_back(gti); } std::string cmd = cmSystemTools::GetCMakeCommand(); - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - singleLine.erase(singleLine.begin(), singleLine.end()); - depends.erase(depends.begin(), depends.end()); + GlobalTargetInfo gti; + gti.Name = this->GetInstallTargetName(); + gti.Message = "Install the project..."; + gti.UsesTerminal = true; + cmCustomCommandLine singleLine; if (this->GetPreinstallTargetName()) { - depends.push_back(this->GetPreinstallTargetName()); + gti.Depends.push_back(this->GetPreinstallTargetName()); } else { const char* noall = mf->GetDefinition("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY"); if (!noall || cmSystemTools::IsOff(noall)) { - depends.push_back(this->GetAllTargetName()); + gti.Depends.push_back(this->GetAllTargetName()); } } if (mf->GetDefinition("CMake_BINARY_DIR") && @@ -2259,40 +2283,39 @@ void cmGlobalGenerator::CreateDefaultGlobalTargets(cmTargets* targets) } singleLine.push_back("-P"); singleLine.push_back("cmake_install.cmake"); - cpackCommandLines.push_back(singleLine); - (*targets)[this->GetInstallTargetName()] = this->CreateGlobalTarget( - this->GetInstallTargetName(), "Install the project...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true); + gti.CommandLines.push_back(singleLine); + targets.push_back(gti); // install_local if (const char* install_local = this->GetInstallLocalTargetName()) { + gti.Name = install_local; + gti.Message = "Installing only the local directory..."; + gti.UsesTerminal = true; + gti.CommandLines.clear(); + cmCustomCommandLine localCmdLine = singleLine; localCmdLine.insert(localCmdLine.begin() + 1, "-DCMAKE_INSTALL_LOCAL_ONLY=1"); - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - cpackCommandLines.push_back(localCmdLine); - (*targets)[install_local] = this->CreateGlobalTarget( - install_local, "Installing only the local directory...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true); + gti.CommandLines.push_back(localCmdLine); + targets.push_back(gti); } // install_strip const char* install_strip = this->GetInstallStripTargetName(); if ((install_strip != CM_NULLPTR) && (mf->IsSet("CMAKE_STRIP"))) { + gti.Name = install_strip; + gti.Message = "Installing the project stripped..."; + gti.UsesTerminal = true; + gti.CommandLines.clear(); + cmCustomCommandLine stripCmdLine = singleLine; stripCmdLine.insert(stripCmdLine.begin() + 1, "-DCMAKE_INSTALL_DO_STRIP=1"); - cpackCommandLines.erase(cpackCommandLines.begin(), - cpackCommandLines.end()); - cpackCommandLines.push_back(stripCmdLine); - - (*targets)[install_strip] = this->CreateGlobalTarget( - install_strip, "Installing the project stripped...", - &cpackCommandLines, depends, CM_NULLPTR, /*uses_terminal*/ true); + gti.CommandLines.push_back(stripCmdLine); + targets.push_back(gti); } } } @@ -2326,14 +2349,12 @@ bool cmGlobalGenerator::UseFolderProperty() return false; } -cmTarget cmGlobalGenerator::CreateGlobalTarget( - const std::string& name, const char* message, - const cmCustomCommandLines* commandLines, std::vector<std::string> depends, - const char* workingDirectory, bool uses_terminal) +cmTarget cmGlobalGenerator::CreateGlobalTarget(GlobalTargetInfo const& gti, + cmMakefile* mf) { // Package - cmTarget target; - target.SetType(cmState::GLOBAL_TARGET, name); + cmTarget target(gti.Name, cmState::GLOBAL_TARGET, cmTarget::VisibilityNormal, + mf); target.SetProperty("EXCLUDE_FROM_ALL", "TRUE"); std::vector<std::string> no_outputs; @@ -2341,12 +2362,14 @@ cmTarget cmGlobalGenerator::CreateGlobalTarget( std::vector<std::string> no_depends; // Store the custom command in the target. cmCustomCommand cc(CM_NULLPTR, no_outputs, no_byproducts, no_depends, - *commandLines, CM_NULLPTR, workingDirectory); - cc.SetUsesTerminal(uses_terminal); + gti.CommandLines, CM_NULLPTR, gti.WorkingDir.c_str()); + cc.SetUsesTerminal(gti.UsesTerminal); target.AddPostBuildCommand(cc); - target.SetProperty("EchoString", message); - std::vector<std::string>::iterator dit; - for (dit = depends.begin(); dit != depends.end(); ++dit) { + if (!gti.Message.empty()) { + target.SetProperty("EchoString", gti.Message.c_str()); + } + for (std::vector<std::string>::const_iterator dit = gti.Depends.begin(); + dit != gti.Depends.end(); ++dit) { target.AddUtility(*dit); } @@ -2556,7 +2579,7 @@ void cmGlobalGenerator::AddRuleHash(const std::vector<std::string>& outputs, // Shorten the output name (in expected use case). cmOutputConverter converter(this->GetMakefiles()[0]->GetStateSnapshot()); std::string fname = converter.ConvertToRelativePath( - outputs[0], cmOutputConverter::HOME_OUTPUT); + this->GetMakefiles()[0]->GetState()->GetBinaryDirectory(), outputs[0]); // Associate the hash with this output. this->RuleHashes[fname] = hash; diff --git a/Source/cmGlobalGenerator.h b/Source/cmGlobalGenerator.h index 1e1479a..f7b2e59 100644 --- a/Source/cmGlobalGenerator.h +++ b/Source/cmGlobalGenerator.h @@ -402,11 +402,30 @@ protected: bool IsExcluded(cmLocalGenerator* root, cmLocalGenerator* gen) const; bool IsExcluded(cmLocalGenerator* root, cmGeneratorTarget* target) const; virtual void InitializeProgressMarks() {} - void CreateDefaultGlobalTargets(cmTargets* targets); - cmTarget CreateGlobalTarget(const std::string& name, const char* message, - const cmCustomCommandLines* commandLines, - std::vector<std::string> depends, - const char* workingDir, bool uses_terminal); + + struct GlobalTargetInfo + { + std::string Name; + std::string Message; + cmCustomCommandLines CommandLines; + std::vector<std::string> Depends; + std::string WorkingDir; + bool UsesTerminal; + GlobalTargetInfo() + : UsesTerminal(false) + { + } + }; + + void CreateDefaultGlobalTargets(std::vector<GlobalTargetInfo>& targets); + + void AddGlobalTarget_Package(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_PackageSource(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_Test(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_EditCache(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_RebuildCache(std::vector<GlobalTargetInfo>& targets); + void AddGlobalTarget_Install(std::vector<GlobalTargetInfo>& targets); + cmTarget CreateGlobalTarget(GlobalTargetInfo const& gti, cmMakefile* mf); std::string FindMakeProgramFile; std::string ConfiguredFilesPath; diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 30a05a0..b913621 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -140,10 +140,10 @@ std::string cmGlobalNinjaGenerator::EncodeDepfileSpace(const std::string& path) void cmGlobalNinjaGenerator::WriteBuild( std::ostream& os, const std::string& comment, const std::string& rule, - const cmNinjaDeps& outputs, const cmNinjaDeps& explicitDeps, - const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, - const cmNinjaVars& variables, const std::string& rspfile, int cmdLineLimit, - bool* usedResponseFile) + const cmNinjaDeps& outputs, const cmNinjaDeps& implicitOuts, + const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, + const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables, + const std::string& rspfile, int cmdLineLimit, bool* usedResponseFile) { // Make sure there is a rule. if (rule.empty()) { @@ -204,6 +204,13 @@ void cmGlobalNinjaGenerator::WriteBuild( this->CombinedBuildOutputs.insert(EncodePath(*i)); } } + if (!implicitOuts.empty()) { + build += " |"; + for (cmNinjaDeps::const_iterator i = implicitOuts.begin(); + i != implicitOuts.end(); ++i) { + build += " " + EncodeIdent(EncodePath(*i), os); + } + } build += ":"; // Write the rule. @@ -244,7 +251,8 @@ void cmGlobalNinjaGenerator::WritePhonyBuild( const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, const cmNinjaVars& variables) { - this->WriteBuild(os, comment, "phony", outputs, explicitDeps, implicitDeps, + this->WriteBuild(os, comment, "phony", outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, variables); } @@ -288,7 +296,8 @@ void cmGlobalNinjaGenerator::WriteCustomCommandBuild( vars["depfile"] = depfile; } this->WriteBuild(*this->BuildFileStream, comment, "CUSTOM_COMMAND", outputs, - deps, cmNinjaDeps(), orderOnly, vars); + /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), + orderOnly, vars); if (this->ComputingUnknownDependencies) { // we need to track every dependency that comes in, since we are trying @@ -330,7 +339,8 @@ void cmGlobalNinjaGenerator::WriteMacOSXContentBuild(const std::string& input, cmNinjaVars vars; this->WriteBuild(*this->BuildFileStream, "", "COPY_OSX_CONTENT", outputs, - deps, cmNinjaDeps(), cmNinjaDeps(), cmNinjaVars()); + /*implicitOuts=*/cmNinjaDeps(), deps, cmNinjaDeps(), + cmNinjaDeps(), cmNinjaVars()); } void cmGlobalNinjaGenerator::WriteRule( @@ -760,8 +770,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaPath(const std::string& path) { cmLocalNinjaGenerator* ng = static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]); - std::string convPath = - ng->ConvertToRelativePath(path, cmOutputConverter::HOME_OUTPUT); + std::string convPath = ng->ConvertToRelativePath( + this->LocalGenerators[0]->GetState()->GetBinaryDirectory(), path); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -774,8 +784,8 @@ std::string cmGlobalNinjaGenerator::ConvertToNinjaFolderRule( { cmLocalNinjaGenerator* ng = static_cast<cmLocalNinjaGenerator*>(this->LocalGenerators[0]); - std::string convPath = - ng->ConvertToRelativePath(path + "/all", cmOutputConverter::HOME); + std::string convPath = ng->ConvertToRelativePath( + this->LocalGenerators[0]->GetState()->GetSourceDirectory(), path + "/all"); convPath = this->NinjaOutputPath(convPath); #ifdef _WIN32 std::replace(convPath.begin(), convPath.end(), '/', '\\'); @@ -1271,6 +1281,7 @@ void cmGlobalNinjaGenerator::WriteTargetRebuildManifest(std::ostream& os) this->WriteBuild(os, "Re-run CMake if any of its inputs changed.", "RERUN_CMAKE", /*outputs=*/cmNinjaDeps(1, ninjaBuildFile), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), implicitDeps, /*orderOnlyDeps=*/cmNinjaDeps(), variables); @@ -1295,6 +1306,13 @@ bool cmGlobalNinjaGenerator::SupportsConsolePool() const RequiredNinjaVersionForConsolePool().c_str()); } +bool cmGlobalNinjaGenerator::SupportsImplicitOuts() const +{ + return !cmSystemTools::VersionCompare( + cmSystemTools::OP_LESS, this->NinjaVersion.c_str(), + this->RequiredNinjaVersionForImplicitOuts().c_str()); +} + void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) { WriteRule(*this->RulesFileStream, "CLEAN", ninjaCmd() + " -t clean", @@ -1308,6 +1326,7 @@ void cmGlobalNinjaGenerator::WriteTargetClean(std::ostream& os) /*generator=*/false); WriteBuild(os, "Clean all the built files.", "CLEAN", /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("clean")), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), /*implicitDeps=*/cmNinjaDeps(), /*orderOnlyDeps=*/cmNinjaDeps(), @@ -1327,6 +1346,7 @@ void cmGlobalNinjaGenerator::WriteTargetHelp(std::ostream& os) /*generator=*/false); WriteBuild(os, "Print all primary targets available.", "HELP", /*outputs=*/cmNinjaDeps(1, this->NinjaOutputPath("help")), + /*implicitOuts=*/cmNinjaDeps(), /*explicitDeps=*/cmNinjaDeps(), /*implicitDeps=*/cmNinjaDeps(), /*orderOnlyDeps=*/cmNinjaDeps(), diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index a0fad64..0201685 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -106,6 +106,7 @@ public: */ void WriteBuild(std::ostream& os, const std::string& comment, const std::string& rule, const cmNinjaDeps& outputs, + const cmNinjaDeps& implicitOuts, const cmNinjaDeps& explicitDeps, const cmNinjaDeps& implicitDeps, const cmNinjaDeps& orderOnlyDeps, @@ -338,7 +339,9 @@ public: // Ninja generator uses 'deps' and 'msvc_deps_prefix' introduced in 1.3 static std::string RequiredNinjaVersion() { return "1.3"; } static std::string RequiredNinjaVersionForConsolePool() { return "1.5"; } + static std::string RequiredNinjaVersionForImplicitOuts() { return "1.7"; } bool SupportsConsolePool() const; + bool SupportsImplicitOuts() const; std::string NinjaOutputPath(std::string const& path); bool HasOutputPathPrefix() const { return !this->OutputPathPrefix.empty(); } diff --git a/Source/cmGlobalUnixMakefileGenerator3.cxx b/Source/cmGlobalUnixMakefileGenerator3.cxx index d90ebf0..52ae469 100644 --- a/Source/cmGlobalUnixMakefileGenerator3.cxx +++ b/Source/cmGlobalUnixMakefileGenerator3.cxx @@ -319,18 +319,15 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() std::string cache = this->GetCMakeInstance()->GetHomeOutputDirectory(); cache += "/CMakeCache.txt"; + std::string currentBinDir = lg->GetCurrentBinaryDirectory(); // Save the list to the cmake file. cmakefileStream << "# The top level Makefile was generated from the following files:\n" << "set(CMAKE_MAKEFILE_DEPENDS\n" - << " \"" - << lg->ConvertToRelativePath(cache, cmOutputConverter::START_OUTPUT) - << "\"\n"; + << " \"" << lg->ConvertToRelativePath(currentBinDir, cache) << "\"\n"; for (std::vector<std::string>::const_iterator i = lfiles.begin(); i != lfiles.end(); ++i) { - cmakefileStream << " \"" - << lg->ConvertToRelativePath( - *i, cmOutputConverter::START_OUTPUT) + cmakefileStream << " \"" << lg->ConvertToRelativePath(currentBinDir, *i) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -344,15 +341,14 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() cmakefileStream << "# The corresponding makefile is:\n" << "set(CMAKE_MAKEFILE_OUTPUTS\n" << " \"" - << lg->ConvertToRelativePath(makefileName, - cmOutputConverter::START_OUTPUT) + << lg->ConvertToRelativePath(currentBinDir, makefileName) << "\"\n" - << " \"" - << lg->ConvertToRelativePath(check, - cmOutputConverter::START_OUTPUT) + << " \"" << lg->ConvertToRelativePath(currentBinDir, check) << "\"\n"; cmakefileStream << " )\n\n"; + const std::string binDir = lg->GetBinaryDirectory(); + // CMake must rerun if a byproduct is missing. { cmakefileStream << "# Byproducts of CMake generate step:\n" @@ -361,9 +357,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() lg->GetMakefile()->GetOutputFiles(); for (std::vector<std::string>::const_iterator k = outfiles.begin(); k != outfiles.end(); ++k) { - cmakefileStream << " \"" - << lg->ConvertToRelativePath( - *k, cmOutputConverter::HOME_OUTPUT) + cmakefileStream << " \"" << lg->ConvertToRelativePath(binDir, *k) << "\"\n"; } @@ -375,9 +369,7 @@ void cmGlobalUnixMakefileGenerator3::WriteMainCMakefile() tmpStr = lg->GetCurrentBinaryDirectory(); tmpStr += cmake::GetCMakeFilesDirectory(); tmpStr += "/CMakeDirectoryInformation.cmake"; - cmakefileStream << " \"" - << lg->ConvertToRelativePath( - tmpStr, cmOutputConverter::HOME_OUTPUT) + cmakefileStream << " \"" << lg->ConvertToRelativePath(binDir, tmpStr) << "\"\n"; } cmakefileStream << " )\n\n"; @@ -488,9 +480,10 @@ void cmGlobalUnixMakefileGenerator3::WriteDirectoryRules2( } // Begin the directory-level rules section. - std::string dir = lg->GetCurrentBinaryDirectory(); - dir = lg->Convert(dir, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE); + std::string dir = cmSystemTools::ConvertToOutputPath( + lg->ConvertToRelativePath(lg->GetBinaryDirectory(), + lg->GetCurrentBinaryDirectory()) + .c_str()); lg->WriteDivider(ruleFileStream); ruleFileStream << "# Directory level rules for directory " << dir << "\n\n"; @@ -538,7 +531,8 @@ void cmGlobalUnixMakefileGenerator3::GenerateBuildCommand( tname += "/fast"; } cmOutputConverter conv(mf->GetStateSnapshot()); - tname = conv.ConvertToRelativePath(tname, cmOutputConverter::HOME_OUTPUT); + tname = + conv.ConvertToRelativePath(mf->GetState()->GetBinaryDirectory(), tname); cmSystemTools::ConvertToOutputSlashes(tname); makeCommand.push_back(tname); if (this->Makefiles.empty()) { diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 0dc4497..7664b02 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -382,6 +382,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( { VisualStudioFolders.clear(); + std::string rootBinaryDir = root->GetCurrentBinaryDirectory(); for (OrderedTargetDependSet::const_iterator tt = projectTargets.begin(); tt != projectTargets.end(); ++tt) { cmGeneratorTarget const* target = *tt; @@ -405,8 +406,7 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( if (vcprojName) { cmLocalGenerator* lg = target->GetLocalGenerator(); std::string dir = lg->GetCurrentBinaryDirectory(); - dir = root->ConvertToRelativePath(dir.c_str(), - cmOutputConverter::START_OUTPUT); + dir = root->ConvertToRelativePath(rootBinaryDir, dir.c_str()); if (dir == ".") { dir = ""; // msbuild cannot handle ".\" prefix } diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 5653820..997f46c 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -896,9 +896,6 @@ void cmGlobalXCodeGenerator::SetCurrentLocalGenerator(cmLocalGenerator* gen) { this->CurrentLocalGenerator = gen; this->CurrentMakefile = gen->GetMakefile(); - std::string outdir = cmSystemTools::CollapseFullPath( - this->CurrentLocalGenerator->GetCurrentBinaryDirectory()); - cmSystemTools::SplitPath(outdir, this->CurrentOutputDirectoryComponents); // Select the current set of configuration types. this->CurrentConfigurationTypes.clear(); diff --git a/Source/cmGlobalXCodeGenerator.h b/Source/cmGlobalXCodeGenerator.h index 303dfa0..ebdba3e 100644 --- a/Source/cmGlobalXCodeGenerator.h +++ b/Source/cmGlobalXCodeGenerator.h @@ -241,7 +241,6 @@ private: std::string CurrentXCodeHackMakefile; std::string CurrentProject; std::set<std::string> TargetDoneSet; - std::vector<std::string> CurrentOutputDirectoryComponents; std::vector<std::string> ProjectSourceDirectoryComponents; std::vector<std::string> ProjectOutputDirectoryComponents; std::map<std::string, cmXCodeObject*> GroupMap; diff --git a/Source/cmHexFileConverter.cxx b/Source/cmHexFileConverter.cxx index 34fd626..64ece2d 100644 --- a/Source/cmHexFileConverter.cxx +++ b/Source/cmHexFileConverter.cxx @@ -89,7 +89,8 @@ static bool ConvertMotorolaSrecLine(const char* buf, FILE* outFile) if ((buf[1] == '5') || (buf[1] == '7') || (buf[1] == '8') || (buf[1] == '9')) { return true; - } else if (buf[1] == '1') { + } + if (buf[1] == '1') { dataStart = 8; } else if (buf[1] == '2') { dataStart = 10; diff --git a/Source/cmIfCommand.cxx b/Source/cmIfCommand.cxx index dd04136..f0143e7 100644 --- a/Source/cmIfCommand.cxx +++ b/Source/cmIfCommand.cxx @@ -190,9 +190,8 @@ bool cmIfCommand::InvokeInitialPass( this->Makefile->IssueMessage(cmake::FATAL_ERROR, err); cmSystemTools::SetFatalErrorOccured(); return true; - } else { - this->Makefile->IssueMessage(status, err); } + this->Makefile->IssueMessage(status, err); } cmIfFunctionBlocker* f = new cmIfFunctionBlocker(); diff --git a/Source/cmIncludeCommand.cxx b/Source/cmIncludeCommand.cxx index 360ebeb..c90314e 100644 --- a/Source/cmIncludeCommand.cxx +++ b/Source/cmIncludeCommand.cxx @@ -15,7 +15,7 @@ bool cmIncludeCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1 || args.size() > 4) { + if (args.empty() || args.size() > 4) { this->SetError("called with wrong number of arguments. " "include() only takes one file."); return false; diff --git a/Source/cmIncludeDirectoryCommand.cxx b/Source/cmIncludeDirectoryCommand.cxx index cafdba7..904fcca 100644 --- a/Source/cmIncludeDirectoryCommand.cxx +++ b/Source/cmIncludeDirectoryCommand.cxx @@ -15,7 +15,7 @@ bool cmIncludeDirectoryCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmIncludeRegularExpressionCommand.cxx b/Source/cmIncludeRegularExpressionCommand.cxx index 2473dff..bd26d93 100644 --- a/Source/cmIncludeRegularExpressionCommand.cxx +++ b/Source/cmIncludeRegularExpressionCommand.cxx @@ -15,7 +15,7 @@ bool cmIncludeRegularExpressionCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if ((args.size() < 1) || (args.size() > 2)) { + if ((args.empty()) || (args.size() > 2)) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 4912eac..8450360 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -71,19 +71,28 @@ bool cmInstallCommand::InitialPass(std::vector<std::string> const& args, // Switch among the command modes. if (args[0] == "SCRIPT") { return this->HandleScriptMode(args); - } else if (args[0] == "CODE") { + } + if (args[0] == "CODE") { return this->HandleScriptMode(args); - } else if (args[0] == "TARGETS") { + } + if (args[0] == "TARGETS") { return this->HandleTargetsMode(args); - } else if (args[0] == "FILES") { + } + if (args[0] == "FILES") { return this->HandleFilesMode(args); - } else if (args[0] == "PROGRAMS") { + } + if (args[0] == "PROGRAMS") { return this->HandleFilesMode(args); - } else if (args[0] == "DIRECTORY") { + } + if (args[0] == "DIRECTORY") { return this->HandleDirectoryMode(args); - } else if (args[0] == "EXPORT") { + } + if (args[0] == "EXPORT") { return this->HandleExportMode(args); } + if (args[0] == "EXPORT_ANDROID_MK") { + return this->HandleExportAndroidMKMode(args); + } // Unknown mode. std::string e = "called with unknown mode "; @@ -338,7 +347,8 @@ bool cmInstallCommand::HandleTargetsMode(std::vector<std::string> const& args) << "\" which is not an executable, library, or module."; this->SetError(e.str()); return false; - } else if (target->GetType() == cmState::OBJECT_LIBRARY) { + } + if (target->GetType() == cmState::OBJECT_LIBRARY) { std::ostringstream e; e << "TARGETS given OBJECT library \"" << (*targetIt) << "\" which may not be installed."; @@ -1097,6 +1107,100 @@ bool cmInstallCommand::HandleDirectoryMode( return true; } +bool cmInstallCommand::HandleExportAndroidMKMode( + std::vector<std::string> const& args) +{ +#ifdef CMAKE_BUILD_WITH_CMAKE + // This is the EXPORT mode. + cmInstallCommandArguments ica(this->DefaultComponentName); + cmCAString exp(&ica.Parser, "EXPORT_ANDROID_MK"); + cmCAString name_space(&ica.Parser, "NAMESPACE", &ica.ArgumentGroup); + cmCAEnabler exportOld(&ica.Parser, "EXPORT_LINK_INTERFACE_LIBRARIES", + &ica.ArgumentGroup); + cmCAString filename(&ica.Parser, "FILE", &ica.ArgumentGroup); + exp.Follows(CM_NULLPTR); + + ica.ArgumentGroup.Follows(&exp); + std::vector<std::string> unknownArgs; + ica.Parse(&args, &unknownArgs); + + if (!unknownArgs.empty()) { + // Unknown argument. + std::ostringstream e; + e << args[0] << " given unknown argument \"" << unknownArgs[0] << "\"."; + this->SetError(e.str()); + return false; + } + + if (!ica.Finalize()) { + return false; + } + + // Make sure there is a destination. + if (ica.GetDestination().empty()) { + // A destination is required. + std::ostringstream e; + e << args[0] << " given no DESTINATION!"; + this->SetError(e.str()); + return false; + } + + // Check the file name. + std::string fname = filename.GetString(); + if (fname.find_first_of(":/\\") != fname.npos) { + std::ostringstream e; + e << args[0] << " given invalid export file name \"" << fname << "\". " + << "The FILE argument may not contain a path. " + << "Specify the path in the DESTINATION argument."; + this->SetError(e.str()); + return false; + } + + // Check the file extension. + if (!fname.empty() && + cmSystemTools::GetFilenameLastExtension(fname) != ".mk") { + std::ostringstream e; + e << args[0] << " given invalid export file name \"" << fname << "\". " + << "The FILE argument must specify a name ending in \".mk\"."; + this->SetError(e.str()); + return false; + } + if (fname.find_first_of(":/\\") != fname.npos) { + std::ostringstream e; + e << args[0] << " given export name \"" << exp.GetString() << "\". " + << "This name cannot be safely converted to a file name. " + << "Specify a different export name or use the FILE option to set " + << "a file name explicitly."; + this->SetError(e.str()); + return false; + } + // Use the default name + if (fname.empty()) { + fname = "Android.mk"; + } + + cmExportSet* exportSet = + this->Makefile->GetGlobalGenerator()->GetExportSets()[exp.GetString()]; + + cmInstallGenerator::MessageLevel message = + cmInstallGenerator::SelectMessageLevel(this->Makefile); + + // Create the export install generator. + cmInstallExportGenerator* exportGenerator = new cmInstallExportGenerator( + exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), + ica.GetConfigurations(), ica.GetComponent().c_str(), message, + ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(), + exportOld.IsEnabled(), true); + this->Makefile->AddInstallGenerator(exportGenerator); + + return true; +#else + static_cast<void>(args); + this->SetError("EXPORT_ANDROID_MK not supported in bootstrap cmake"); + return false; +#endif +} + bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) { // This is the EXPORT mode. @@ -1203,7 +1307,7 @@ bool cmInstallCommand::HandleExportMode(std::vector<std::string> const& args) exportSet, ica.GetDestination().c_str(), ica.GetPermissions().c_str(), ica.GetConfigurations(), ica.GetComponent().c_str(), message, ica.GetExcludeFromAll(), fname.c_str(), name_space.GetCString(), - exportOld.IsEnabled()); + exportOld.IsEnabled(), false); this->Makefile->AddInstallGenerator(exportGenerator); return true; diff --git a/Source/cmInstallCommand.h b/Source/cmInstallCommand.h index 3718ad5..7bc974c 100644 --- a/Source/cmInstallCommand.h +++ b/Source/cmInstallCommand.h @@ -48,6 +48,7 @@ private: bool HandleFilesMode(std::vector<std::string> const& args); bool HandleDirectoryMode(std::vector<std::string> const& args); bool HandleExportMode(std::vector<std::string> const& args); + bool HandleExportAndroidMKMode(std::vector<std::string> const& args); bool MakeFilesFullPath(const char* modeName, const std::vector<std::string>& relFiles, std::vector<std::string>& absFiles); diff --git a/Source/cmInstallExportAndroidMKGenerator.cxx b/Source/cmInstallExportAndroidMKGenerator.cxx new file mode 100644 index 0000000..43bdc01 --- /dev/null +++ b/Source/cmInstallExportAndroidMKGenerator.cxx @@ -0,0 +1,149 @@ + +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmInstallExportAndroidMKGenerator.h" + +#include <stdio.h> + +#include "cmExportInstallFileGenerator.h" +#include "cmExportSet.h" +#include "cmGeneratedFileStream.h" +#include "cmGlobalGenerator.h" +#include "cmInstallFilesGenerator.h" +#include "cmInstallTargetGenerator.h" +#include "cmLocalGenerator.h" +#include "cmMakefile.h" +#include "cmake.h" + +cmInstallExportAndroidMKGenerator::cmInstallExportAndroidMKGenerator( + cmExportSet* exportSet, const char* destination, + const char* file_permissions, std::vector<std::string> const& configurations, + const char* component, MessageLevel message, bool exclude_from_all, + const char* filename, const char* name_space, bool exportOld) + : cmInstallExportGenerator(exportSet, destination, file_permissions, + configurations, component, message, + exclude_from_all, filename, name_space, exportOld) +{ +} + +cmInstallExportAndroidMKGenerator::~cmInstallExportAndroidMKGenerator() +{ +} + +void cmInstallExportAndroidMKGenerator::Compute(cmLocalGenerator* lg) +{ + this->LocalGenerator = lg; + this->ExportSet->Compute(lg); +} + +void cmInstallExportAndroidMKGenerator::GenerateScript(std::ostream& os) +{ + // Skip empty sets. + if (ExportSet->GetTargetExports()->empty()) { + std::ostringstream e; + e << "INSTALL(EXPORT) given unknown export \"" << ExportSet->GetName() + << "\""; + cmSystemTools::Error(e.str().c_str()); + return; + } + + // Create the temporary directory in which to store the files. + this->ComputeTempDir(); + cmSystemTools::MakeDirectory(this->TempDir.c_str()); + + // Construct a temporary location for the file. + this->MainImportFile = this->TempDir; + this->MainImportFile += "/"; + this->MainImportFile += this->FileName; + + // Generate the import file for this export set. + this->EFGen->SetExportFile(this->MainImportFile.c_str()); + this->EFGen->SetNamespace(this->Namespace); + this->EFGen->SetExportOld(this->ExportOld); + if (this->ConfigurationTypes->empty()) { + if (!this->ConfigurationName.empty()) { + this->EFGen->AddConfiguration(this->ConfigurationName); + } else { + this->EFGen->AddConfiguration(""); + } + } else { + for (std::vector<std::string>::const_iterator ci = + this->ConfigurationTypes->begin(); + ci != this->ConfigurationTypes->end(); ++ci) { + this->EFGen->AddConfiguration(*ci); + } + } + this->EFGen->GenerateImportFile(); + + // Perform the main install script generation. + this->cmInstallGenerator::GenerateScript(os); +} + +void cmInstallExportAndroidMKGenerator::GenerateScriptConfigs( + std::ostream& os, Indent const& indent) +{ + // Create the main install rules first. + this->cmInstallGenerator::GenerateScriptConfigs(os, indent); + + // Now create a configuration-specific install rule for the import + // file of each configuration. + std::vector<std::string> files; + for (std::map<std::string, std::string>::const_iterator i = + this->EFGen->GetConfigImportFiles().begin(); + i != this->EFGen->GetConfigImportFiles().end(); ++i) { + files.push_back(i->second); + std::string config_test = this->CreateConfigTest(i->first); + os << indent << "if(" << config_test << ")\n"; + this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files, + false, this->FilePermissions.c_str(), CM_NULLPTR, + CM_NULLPTR, CM_NULLPTR, indent.Next()); + os << indent << "endif()\n"; + files.clear(); + } +} + +void cmInstallExportAndroidMKGenerator::GenerateScriptActions( + std::ostream& os, Indent const& indent) +{ + // Remove old per-configuration export files if the main changes. + std::string installedDir = "$ENV{DESTDIR}"; + installedDir += this->ConvertToAbsoluteDestination(this->Destination); + installedDir += "/"; + std::string installedFile = installedDir; + installedFile += this->FileName; + os << indent << "if(EXISTS \"" << installedFile << "\")\n"; + Indent indentN = indent.Next(); + Indent indentNN = indentN.Next(); + Indent indentNNN = indentNN.Next(); + /* clang-format off */ + os << indentN << "file(DIFFERENT EXPORT_FILE_CHANGED FILES\n" + << indentN << " \"" << installedFile << "\"\n" + << indentN << " \"" << this->MainImportFile << "\")\n"; + os << indentN << "if(EXPORT_FILE_CHANGED)\n"; + os << indentNN << "file(GLOB OLD_CONFIG_FILES \"" << installedDir + << this->EFGen->GetConfigImportFileGlob() << "\")\n"; + os << indentNN << "if(OLD_CONFIG_FILES)\n"; + os << indentNNN << "message(STATUS \"Old export file \\\"" << installedFile + << "\\\" will be replaced. Removing files [${OLD_CONFIG_FILES}].\")\n"; + os << indentNNN << "file(REMOVE ${OLD_CONFIG_FILES})\n"; + os << indentNN << "endif()\n"; + os << indentN << "endif()\n"; + os << indent << "endif()\n"; + /* clang-format on */ + + // Install the main export file. + std::vector<std::string> files; + files.push_back(this->MainImportFile); + this->AddInstallRule(os, this->Destination, cmInstallType_FILES, files, + false, this->FilePermissions.c_str(), CM_NULLPTR, + CM_NULLPTR, CM_NULLPTR, indent); +} diff --git a/Source/cmInstallExportAndroidMKGenerator.h b/Source/cmInstallExportAndroidMKGenerator.h new file mode 100644 index 0000000..158972d --- /dev/null +++ b/Source/cmInstallExportAndroidMKGenerator.h @@ -0,0 +1,46 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2009 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef cmInstallExportAndroidMKGenerator_h +#define cmInstallExportAndroidMKGenerator_h + +#include "cmInstallExportGenerator.h" + +class cmExportInstallFileGenerator; +class cmInstallFilesGenerator; +class cmInstallTargetGenerator; +class cmExportSet; +class cmMakefile; + +/** \class cmInstallExportAndroidMKGenerator + * \brief Generate rules for creating an export files. + */ +class cmInstallExportAndroidMKGenerator : public cmInstallExportGenerator +{ +public: + cmInstallExportAndroidMKGenerator( + cmExportSet* exportSet, const char* dest, const char* file_permissions, + const std::vector<std::string>& configurations, const char* component, + MessageLevel message, bool exclude_from_all, const char* filename, + const char* name_space, bool exportOld); + ~cmInstallExportAndroidMKGenerator(); + + void Compute(cmLocalGenerator* lg); + +protected: + virtual void GenerateScript(std::ostream& os); + virtual void GenerateScriptConfigs(std::ostream& os, Indent const& indent); + virtual void GenerateScriptActions(std::ostream& os, Indent const& indent); + void GenerateImportFile(cmExportSet const* exportSet); + void GenerateImportFile(const char* config, cmExportSet const* exportSet); +}; + +#endif diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 27628f4..5ea7faf 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -16,6 +16,9 @@ #include <sstream> #include <utility> +#ifdef CMAKE_BUILD_WITH_CMAKE +#include "cmExportInstallAndroidMKGenerator.h" +#endif #include "cmExportInstallFileGenerator.h" #include "cmExportSet.h" #include "cmInstallType.h" @@ -27,7 +30,7 @@ cmInstallExportGenerator::cmInstallExportGenerator( cmExportSet* exportSet, const char* destination, const char* file_permissions, std::vector<std::string> const& configurations, const char* component, MessageLevel message, bool exclude_from_all, - const char* filename, const char* name_space, bool exportOld) + const char* filename, const char* name_space, bool exportOld, bool android) : cmInstallGenerator(destination, configurations, component, message, exclude_from_all) , ExportSet(exportSet) @@ -37,7 +40,13 @@ cmInstallExportGenerator::cmInstallExportGenerator( , ExportOld(exportOld) , LocalGenerator(CM_NULLPTR) { - this->EFGen = new cmExportInstallFileGenerator(this); + if (android) { +#ifdef CMAKE_BUILD_WITH_CMAKE + this->EFGen = new cmExportInstallAndroidMKGenerator(this); +#endif + } else { + this->EFGen = new cmExportInstallFileGenerator(this); + } exportSet->AddInstallation(this); } diff --git a/Source/cmInstallExportGenerator.h b/Source/cmInstallExportGenerator.h index 5539827..ac02386 100644 --- a/Source/cmInstallExportGenerator.h +++ b/Source/cmInstallExportGenerator.h @@ -37,7 +37,8 @@ public: const std::vector<std::string>& configurations, const char* component, MessageLevel message, bool exclude_from_all, const char* filename, - const char* name_space, bool exportOld); + const char* name_space, bool exportOld, + bool android); ~cmInstallExportGenerator() CM_OVERRIDE; cmExportSet* GetExportSet() { return this->ExportSet; } diff --git a/Source/cmInstallFilesCommand.cxx b/Source/cmInstallFilesCommand.cxx index 64efe61..9d0db02 100644 --- a/Source/cmInstallFilesCommand.cxx +++ b/Source/cmInstallFilesCommand.cxx @@ -143,12 +143,12 @@ std::string cmInstallFilesCommand::FindInstallSource(const char* name) const if (cmSystemTools::FileExists(tb.c_str())) { // The file exists in the binary tree. Use it. return tb; - } else if (cmSystemTools::FileExists(ts.c_str())) { + } + if (cmSystemTools::FileExists(ts.c_str())) { // The file exists in the source tree. Use it. return ts; - } else { - // The file doesn't exist. Assume it will be present in the - // binary tree when the install occurs. - return tb; } + // The file doesn't exist. Assume it will be present in the + // binary tree when the install occurs. + return tb; } diff --git a/Source/cmInstallProgramsCommand.cxx b/Source/cmInstallProgramsCommand.cxx index 2e5fc1f..93e7f6c 100644 --- a/Source/cmInstallProgramsCommand.cxx +++ b/Source/cmInstallProgramsCommand.cxx @@ -113,12 +113,12 @@ std::string cmInstallProgramsCommand::FindInstallSource(const char* name) const if (cmSystemTools::FileExists(tb.c_str())) { // The file exists in the binary tree. Use it. return tb; - } else if (cmSystemTools::FileExists(ts.c_str())) { + } + if (cmSystemTools::FileExists(ts.c_str())) { // The file exists in the source tree. Use it. return ts; - } else { - // The file doesn't exist. Assume it will be present in the - // binary tree when the install occurs. - return tb; } + // The file doesn't exist. Assume it will be present in the + // binary tree when the install occurs. + return tb; } diff --git a/Source/cmInstallTargetsCommand.cxx b/Source/cmInstallTargetsCommand.cxx index 056ea24..6b594b6 100644 --- a/Source/cmInstallTargetsCommand.cxx +++ b/Source/cmInstallTargetsCommand.cxx @@ -37,14 +37,17 @@ bool cmInstallTargetsCommand::InitialPass(std::vector<std::string> const& args, } runtime_dir = *s; - } else if (tgts.find(*s) != tgts.end()) { - tgts[*s].SetInstallPath(args[0].c_str()); - tgts[*s].SetRuntimeInstallPath(runtime_dir.c_str()); - tgts[*s].SetHaveInstallRule(true); } else { - std::string str = "Cannot find target: \"" + *s + "\" to install."; - this->SetError(str); - return false; + cmTargets::iterator ti = tgts.find(*s); + if (ti != tgts.end()) { + ti->second.SetInstallPath(args[0].c_str()); + ti->second.SetRuntimeInstallPath(runtime_dir.c_str()); + ti->second.SetHaveInstallRule(true); + } else { + std::string str = "Cannot find target: \"" + *s + "\" to install."; + this->SetError(str); + return false; + } } } diff --git a/Source/cmLinkDirectoriesCommand.cxx b/Source/cmLinkDirectoriesCommand.cxx index a33b429..9b5d54a 100644 --- a/Source/cmLinkDirectoriesCommand.cxx +++ b/Source/cmLinkDirectoriesCommand.cxx @@ -15,7 +15,7 @@ bool cmLinkDirectoriesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmLinkLibrariesCommand.cxx b/Source/cmLinkLibrariesCommand.cxx index 5d23d6a..bef234e 100644 --- a/Source/cmLinkLibrariesCommand.cxx +++ b/Source/cmLinkLibrariesCommand.cxx @@ -15,7 +15,7 @@ bool cmLinkLibrariesCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { return true; } // add libraries, nothe that there is an optional prefix diff --git a/Source/cmLinkedTree.h b/Source/cmLinkedTree.h index 466aaa7..025c0a3 100644 --- a/Source/cmLinkedTree.h +++ b/Source/cmLinkedTree.h @@ -167,10 +167,10 @@ public: iterator Truncate() { - assert(this->UpPositions.size() > 0); + assert(!this->UpPositions.empty()); this->UpPositions.erase(this->UpPositions.begin() + 1, this->UpPositions.end()); - assert(this->Data.size() > 0); + assert(!this->Data.empty()); this->Data.erase(this->Data.begin() + 1, this->Data.end()); return iterator(this, 1); } diff --git a/Source/cmListFileCache.cxx b/Source/cmListFileCache.cxx index 14bb81e..7ab7de1 100644 --- a/Source/cmListFileCache.cxx +++ b/Source/cmListFileCache.cxx @@ -404,8 +404,8 @@ void cmListFileBacktrace::PrintTitle(std::ostream& out) const cmOutputConverter converter(this->Bottom); cmListFileContext lfc = *this->Cur; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.ConvertToRelativePath( + this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } out << (lfc.Line ? " at " : " in ") << lfc; } @@ -430,8 +430,8 @@ void cmListFileBacktrace::PrintCallStack(std::ostream& out) const } cmListFileContext lfc = *i; if (!this->Bottom.GetState()->GetIsInTryCompile()) { - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.ConvertToRelativePath( + this->Bottom.GetState()->GetSourceDirectory(), lfc.FilePath); } out << " " << lfc << "\n"; } diff --git a/Source/cmLoadCacheCommand.cxx b/Source/cmLoadCacheCommand.cxx index 85188d1..6d9cf8e 100644 --- a/Source/cmLoadCacheCommand.cxx +++ b/Source/cmLoadCacheCommand.cxx @@ -18,7 +18,7 @@ bool cmLoadCacheCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with wrong number of arguments."); } diff --git a/Source/cmLoadCommandCommand.cxx b/Source/cmLoadCommandCommand.cxx index ddf6ce6..4d8a4e3 100644 --- a/Source/cmLoadCommandCommand.cxx +++ b/Source/cmLoadCommandCommand.cxx @@ -183,7 +183,7 @@ bool cmLoadCommandCommand::InitialPass(std::vector<std::string> const& args, "The load_command command should not be called; see CMP0031.")) { return true; } - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmLocalCommonGenerator.cxx b/Source/cmLocalCommonGenerator.cxx index 0e79293..b75ce62 100644 --- a/Source/cmLocalCommonGenerator.cxx +++ b/Source/cmLocalCommonGenerator.cxx @@ -18,8 +18,9 @@ class cmGlobalGenerator; -cmLocalCommonGenerator::cmLocalCommonGenerator( - cmGlobalGenerator* gg, cmMakefile* mf, cmOutputConverter::RelativeRoot wd) +cmLocalCommonGenerator::cmLocalCommonGenerator(cmGlobalGenerator* gg, + cmMakefile* mf, + std::string const& wd) : cmLocalGenerator(gg, mf) , WorkingDirectory(wd) { @@ -53,10 +54,12 @@ std::string cmLocalCommonGenerator::GetTargetFortranFlags( } // Add a module output directory flag if necessary. - std::string mod_dir = target->GetFortranModuleDirectory(); + std::string mod_dir = + target->GetFortranModuleDirectory(this->WorkingDirectory); if (!mod_dir.empty()) { - mod_dir = - this->Convert(mod_dir, this->WorkingDirectory, cmOutputConverter::SHELL); + mod_dir = this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->WorkingDirectory, mod_dir), + cmOutputConverter::SHELL); } else { mod_dir = this->Makefile->GetSafeDefinition("CMAKE_Fortran_MODDIR_DEFAULT"); diff --git a/Source/cmLocalCommonGenerator.h b/Source/cmLocalCommonGenerator.h index 9012afd..9454739 100644 --- a/Source/cmLocalCommonGenerator.h +++ b/Source/cmLocalCommonGenerator.h @@ -30,21 +30,18 @@ class cmLocalCommonGenerator : public cmLocalGenerator { public: cmLocalCommonGenerator(cmGlobalGenerator* gg, cmMakefile* mf, - cmOutputConverter::RelativeRoot wd); + std::string const& wd); ~cmLocalCommonGenerator() CM_OVERRIDE; std::string const& GetConfigName() { return this->ConfigName; } - cmOutputConverter::RelativeRoot GetWorkingDirectory() const - { - return this->WorkingDirectory; - } + std::string GetWorkingDirectory() const { return this->WorkingDirectory; } std::string GetTargetFortranFlags(cmGeneratorTarget const* target, std::string const& config) CM_OVERRIDE; protected: - cmOutputConverter::RelativeRoot WorkingDirectory; + std::string WorkingDirectory; void SetConfigName(); std::string ConfigName; diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 694a9f6..9b12354 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -175,15 +175,15 @@ void cmLocalGenerator::GenerateTestFiles() (*gi)->Compute(this); (*gi)->Generate(fout, config, configurationTypes); } - size_t i; - std::vector<cmState::Snapshot> children = - this->Makefile->GetStateSnapshot().GetChildren(); - for (i = 0; i < children.size(); ++i) { + typedef std::vector<cmState::Snapshot> vec_t; + vec_t const& children = this->Makefile->GetStateSnapshot().GetChildren(); + std::string parentBinDir = this->GetCurrentBinaryDirectory(); + for (vec_t::const_iterator i = children.begin(); i != children.end(); ++i) { // TODO: Use add_subdirectory instead? - fout << "subdirs("; - std::string outP = children[i].GetDirectory().GetCurrentBinary(); - fout << this->ConvertToRelativePath(outP, START_OUTPUT); - fout << ")" << std::endl; + std::string outP = i->GetDirectory().GetCurrentBinary(); + outP = this->ConvertToRelativePath(parentBinDir, outP); + outP = cmOutputConverter::EscapeForCMake(outP); + fout << "subdirs(" << outP << ")" << std::endl; } } @@ -1409,7 +1409,9 @@ std::string cmLocalGenerator::ConvertToLinkReference(std::string const& lib, #endif // Normal behavior. - return this->Convert(lib, START_OUTPUT, format); + return this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), lib), + format); } /** @@ -1531,9 +1533,6 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, linkLibs += " "; } - // Write the library flags to the build rule. - fout << linkLibs; - // Check what kind of rpath flags to use. if (cli.GetRuntimeSep().empty()) { // Each rpath entry gets its own option ("-R a -R b -R c") @@ -1560,6 +1559,9 @@ void cmLocalGenerator::OutputLinkLibraries(std::string& linkLibraries, } } + // Write the library flags to the build rule. + fout << linkLibs; + // Add the linker runtime search path if any. std::string rpath_link = cli.GetRPathLinkString(); if (!cli.GetRPathLinkFlag().empty() && !rpath_link.empty()) { @@ -2243,11 +2245,11 @@ std::string cmLocalGenerator::ConstructComment( std::string comment; comment = "Generating "; const char* sep = ""; + std::string currentBinaryDir = this->GetCurrentBinaryDirectory(); for (std::vector<std::string>::const_iterator o = ccg.GetOutputs().begin(); o != ccg.GetOutputs().end(); ++o) { comment += sep; - comment += - this->ConvertToRelativePath(*o, cmOutputConverter::START_OUTPUT); + comment += this->ConvertToRelativePath(currentBinaryDir, *o); sep = ", "; } return comment; @@ -2515,14 +2517,15 @@ std::string cmLocalGenerator::GetObjectFileNameWithoutTarget( const char* fullPath = source.GetFullPath().c_str(); // Try referencing the source relative to the source tree. - std::string relFromSource = this->ConvertToRelativePath(fullPath, START); + std::string relFromSource = + this->ConvertToRelativePath(this->GetCurrentSourceDirectory(), fullPath); assert(!relFromSource.empty()); bool relSource = !cmSystemTools::FileIsFullPath(relFromSource.c_str()); bool subSource = relSource && relFromSource[0] != '.'; // Try referencing the source relative to the binary tree. std::string relFromBinary = - this->ConvertToRelativePath(fullPath, START_OUTPUT); + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), fullPath); assert(!relFromBinary.empty()); bool relBinary = !cmSystemTools::FileIsFullPath(relFromBinary.c_str()); bool subBinary = relBinary && relFromBinary[0] != '.'; diff --git a/Source/cmLocalNinjaGenerator.cxx b/Source/cmLocalNinjaGenerator.cxx index 6793f84..82e4d2c 100644 --- a/Source/cmLocalNinjaGenerator.cxx +++ b/Source/cmLocalNinjaGenerator.cxx @@ -34,7 +34,7 @@ cmLocalNinjaGenerator::cmLocalNinjaGenerator(cmGlobalGenerator* gg, cmMakefile* mf) - : cmLocalCommonGenerator(gg, mf, cmOutputConverter::HOME_OUTPUT) + : cmLocalCommonGenerator(gg, mf, mf->GetState()->GetBinaryDirectory()) , HomeRelativeOutputPath("") { this->TargetImplib = "$TARGET_IMPLIB"; @@ -51,7 +51,7 @@ void cmLocalNinjaGenerator::Generate() // Compute the path to use when referencing the current output // directory from the top output directory. this->HomeRelativeOutputPath = this->ConvertToRelativePath( - this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); + this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; } @@ -145,7 +145,8 @@ std::string cmLocalNinjaGenerator::ConvertToIncludeReference( return this->ConvertToOutputFormat(cmSystemTools::CollapseFullPath(path), format); } - return this->Convert(path, cmOutputConverter::HOME_OUTPUT, format); + return this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetBinaryDirectory(), path), format); } // Private methods. @@ -499,8 +500,10 @@ std::string cmLocalNinjaGenerator::MakeCustomLauncher( const std::vector<std::string>& outputs = ccg.GetOutputs(); if (!outputs.empty()) { if (ccg.GetWorkingDirectory().empty()) { - output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + output = this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), + outputs[0]), + cmOutputConverter::SHELL); } else { output = this->ConvertToOutputFormat(outputs[0], cmOutputConverter::SHELL); diff --git a/Source/cmLocalUnixMakefileGenerator3.cxx b/Source/cmLocalUnixMakefileGenerator3.cxx index 611c502..23d1571 100644 --- a/Source/cmLocalUnixMakefileGenerator3.cxx +++ b/Source/cmLocalUnixMakefileGenerator3.cxx @@ -94,7 +94,7 @@ static std::string cmSplitExtension(std::string const& in, std::string& base) cmLocalUnixMakefileGenerator3::cmLocalUnixMakefileGenerator3( cmGlobalGenerator* gg, cmMakefile* mf) - : cmLocalCommonGenerator(gg, mf, cmOutputConverter::START_OUTPUT) + : cmLocalCommonGenerator(gg, mf, mf->GetCurrentBinaryDirectory()) { this->MakefileVariableSize = 0; this->ColorMakefile = false; @@ -151,7 +151,7 @@ void cmLocalUnixMakefileGenerator3::ComputeHomeRelativeOutputPath() // Compute the path to use when referencing the current output // directory from the top output directory. this->HomeRelativeOutputPath = this->ConvertToRelativePath( - this->GetCurrentBinaryDirectory(), cmOutputConverter::HOME_OUTPUT); + this->GetBinaryDirectory(), this->GetCurrentBinaryDirectory()); if (this->HomeRelativeOutputPath == ".") { this->HomeRelativeOutputPath = ""; } @@ -556,8 +556,8 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } // Construct the left hand side of the rule. - std::string tgt = this->Convert(target, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE); + std::string tgt = cmSystemTools::ConvertToOutputPath( + this->ConvertToRelativePath(this->GetBinaryDirectory(), target).c_str()); const char* space = ""; if (tgt.size() == 1) { @@ -581,11 +581,12 @@ void cmLocalUnixMakefileGenerator3::WriteMakeRule( } else { // Split dependencies into multiple rule lines. This allows for // very long dependency lists even on older make implementations. + std::string binDir = this->GetBinaryDirectory(); for (std::vector<std::string>::const_iterator dep = depends.begin(); dep != depends.end(); ++dep) { replace = *dep; - replace = this->Convert(replace, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE); + replace = cmSystemTools::ConvertToOutputPath( + this->ConvertToRelativePath(binDir, replace).c_str()); os << cmMakeSafe(tgt) << space << ": " << cmMakeSafe(replace) << "\n"; } } @@ -952,6 +953,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // Add each command line to the set of commands. std::vector<std::string> commands1; + std::string currentBinDir = this->GetCurrentBinaryDirectory(); for (unsigned int c = 0; c < ccg.GetNumberOfCommands(); ++c) { // Build the command line in a single string. std::string cmd = ccg.GetCommand(c); @@ -976,8 +978,7 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( // working directory will be the start-output directory. bool had_slash = cmd.find('/') != cmd.npos; if (workingDir.empty()) { - cmd = - this->ConvertToRelativePath(cmd, cmOutputConverter::START_OUTPUT); + cmd = this->ConvertToRelativePath(currentBinDir, cmd); } bool has_slash = cmd.find('/') != cmd.npos; if (had_slash && !has_slash) { @@ -1001,8 +1002,10 @@ void cmLocalUnixMakefileGenerator3::AppendCustomCommand( const std::vector<std::string>& outputs = ccg.GetOutputs(); if (!outputs.empty()) { if (workingDir.empty()) { - output = this->Convert(outputs[0], cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + output = this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), + outputs[0]), + cmOutputConverter::SHELL); } else { output = this->ConvertToOutputFormat(outputs[0], @@ -1069,7 +1072,8 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( std::vector<std::string>& commands, const std::vector<std::string>& files, cmGeneratorTarget* target, const char* filename) { - std::string cleanfile = this->GetCurrentBinaryDirectory(); + std::string currentBinDir = this->GetCurrentBinaryDirectory(); + std::string cleanfile = currentBinDir; cleanfile += "/"; cleanfile += this->GetTargetDirectory(target); cleanfile += "/cmake_clean"; @@ -1087,15 +1091,15 @@ void cmLocalUnixMakefileGenerator3::AppendCleanCommand( fout << "file(REMOVE_RECURSE\n"; for (std::vector<std::string>::const_iterator f = files.begin(); f != files.end(); ++f) { - std::string fc = - this->ConvertToRelativePath(*f, cmOutputConverter::START_OUTPUT); + std::string fc = this->ConvertToRelativePath(currentBinDir, *f); fout << " " << cmOutputConverter::EscapeForCMake(fc) << "\n"; } fout << ")\n"; } std::string remove = "$(CMAKE_COMMAND) -P "; - remove += this->Convert(cleanfile, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + remove += this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), cleanfile), + cmOutputConverter::SHELL); commands.push_back(remove); // For the main clean rule add per-language cleaning. @@ -1853,9 +1857,9 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( const std::string& config = this->Makefile->GetSafeDefinition("CMAKE_BUILD_TYPE"); this->GetIncludeDirectories(includes, target, l->first, config); + std::string binaryDir = this->GetState()->GetBinaryDirectory(); if (this->Makefile->IsOn("CMAKE_DEPENDS_IN_PROJECT_ONLY")) { const char* sourceDir = this->GetState()->GetSourceDirectory(); - const char* binaryDir = this->GetState()->GetBinaryDirectory(); std::vector<std::string>::iterator itr = std::remove_if(includes.begin(), includes.end(), ::NotInProjectDir(sourceDir, binaryDir)); @@ -1863,9 +1867,7 @@ void cmLocalUnixMakefileGenerator3::WriteDependLanguageInfo( } for (std::vector<std::string>::iterator i = includes.begin(); i != includes.end(); ++i) { - cmakefileStream << " \"" - << this->ConvertToRelativePath( - *i, cmOutputConverter::HOME_OUTPUT) + cmakefileStream << " \"" << this->ConvertToRelativePath(binaryDir, *i) << "\"\n"; } cmakefileStream << " )\n"; @@ -1930,7 +1932,7 @@ std::string cmLocalUnixMakefileGenerator3::GetRecursiveMakeCall( if (!tgt.empty()) { // The make target is always relative to the top of the build tree. std::string tgt2 = - this->ConvertToRelativePath(tgt, cmOutputConverter::HOME_OUTPUT); + this->ConvertToRelativePath(this->GetBinaryDirectory(), tgt); // The target may have been written with windows paths. cmSystemTools::ConvertToOutputSlashes(tgt2); diff --git a/Source/cmLocalVisualStudio7Generator.cxx b/Source/cmLocalVisualStudio7Generator.cxx index 70fe819..f477a0e 100644 --- a/Source/cmLocalVisualStudio7Generator.cxx +++ b/Source/cmLocalVisualStudio7Generator.cxx @@ -788,8 +788,8 @@ void cmLocalVisualStudio7Generator::WriteConfiguration( target->GetProperty("Fortran_MODULE_DIRECTORY"); std::string modDir; if (target_mod_dir) { - modDir = this->ConvertToRelativePath(target_mod_dir, - cmOutputConverter::START_OUTPUT); + modDir = this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), + target_mod_dir); } else { modDir = "."; } @@ -1298,10 +1298,11 @@ void cmLocalVisualStudio7GeneratorInternals::OutputLibraries( std::ostream& fout, ItemVector const& libs) { cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + std::string currentBinDir = lg->GetCurrentBinaryDirectory(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { - std::string rel = lg->ConvertToRelativePath( - l->Value.c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = + lg->ConvertToRelativePath(currentBinDir, l->Value.c_str()); fout << lg->ConvertToXMLOutputPath(rel.c_str()) << " "; } else if (!l->Target || l->Target->GetType() != cmState::INTERFACE_LIBRARY) { @@ -1316,13 +1317,13 @@ void cmLocalVisualStudio7GeneratorInternals::OutputObjects( // VS < 8 does not support per-config source locations so we // list object library content on the link line instead. cmLocalVisualStudio7Generator* lg = this->LocalGenerator; + std::string currentBinDir = lg->GetCurrentBinaryDirectory(); std::vector<std::string> objs; gt->UseObjectLibraries(objs, ""); const char* sep = isep ? isep : ""; for (std::vector<std::string>::const_iterator oi = objs.begin(); oi != objs.end(); ++oi) { - std::string rel = - lg->ConvertToRelativePath(oi->c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = lg->ConvertToRelativePath(currentBinDir, oi->c_str()); fout << sep << lg->ConvertToXMLOutputPath(rel.c_str()); sep = " "; } @@ -1332,6 +1333,7 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( std::ostream& fout, std::vector<std::string> const& dirs) { const char* comma = ""; + std::string currentBinDir = this->GetCurrentBinaryDirectory(); for (std::vector<std::string>::const_iterator d = dirs.begin(); d != dirs.end(); ++d) { // Remove any trailing slash and skip empty paths. @@ -1345,8 +1347,8 @@ void cmLocalVisualStudio7Generator::OutputLibraryDirectories( // Switch to a relative path specification if it is shorter. if (cmSystemTools::FileIsFullPath(dir.c_str())) { - std::string rel = this->ConvertToRelativePath( - dir.c_str(), cmOutputConverter::START_OUTPUT); + std::string rel = + this->ConvertToRelativePath(currentBinDir, dir.c_str()); if (rel.size() < dir.size()) { dir = rel; } diff --git a/Source/cmLocalVisualStudioGenerator.cxx b/Source/cmLocalVisualStudioGenerator.cxx index d344dc5..77ec6f7 100644 --- a/Source/cmLocalVisualStudioGenerator.cxx +++ b/Source/cmLocalVisualStudioGenerator.cxx @@ -205,7 +205,9 @@ std::string cmLocalVisualStudioGenerator::ConstructScript( } if (workingDirectory.empty()) { - script += this->Convert(cmd.c_str(), START_OUTPUT, SHELL); + script += this->ConvertToOutputFormat( + this->ConvertToRelativePath(this->GetCurrentBinaryDirectory(), cmd), + cmOutputConverter::SHELL); } else { script += this->ConvertToOutputFormat(cmd.c_str(), SHELL); } diff --git a/Source/cmMacroCommand.cxx b/Source/cmMacroCommand.cxx index ee9dc8a..033f549 100644 --- a/Source/cmMacroCommand.cxx +++ b/Source/cmMacroCommand.cxx @@ -203,10 +203,9 @@ bool cmMacroFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, // remove the function blocker now that the macro is defined mf.RemoveFunctionBlocker(this, lff); return true; - } else { - // decrement for each nested macro that ends - this->Depth--; } + // decrement for each nested macro that ends + this->Depth--; } // if it wasn't an endmacro and we are not executing then we must be @@ -236,7 +235,7 @@ bool cmMacroFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, bool cmMacroCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index e5a5e6e..50e7b33 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -979,8 +979,9 @@ void cmMakefile::AddCustomCommandOldStyle( // then add the source to the target to make sure the rule is // included. if (sf && !sf->GetPropertyAsBool("__CMAKE_RULE")) { - if (this->Targets.find(target) != this->Targets.end()) { - this->Targets[target].AddSource(sf->GetFullPath()); + cmTargets::iterator ti = this->Targets.find(target); + if (ti != this->Targets.end()) { + ti->second.AddSource(sf->GetFullPath()); } else { cmSystemTools::Error("Attempt to add a custom rule to a target " "that does not exist yet for target ", @@ -1924,11 +1925,12 @@ cmTarget* cmMakefile::AddNewTarget(cmState::TargetType type, const std::string& name) { cmTargets::iterator it = - this->Targets.insert(cmTargets::value_type(name, cmTarget())).first; - cmTarget& target = it->second; - target.SetType(type, name); - target.SetMakefile(this); + this->Targets + .insert(cmTargets::value_type( + name, cmTarget(name, type, cmTarget::VisibilityNormal, this))) + .first; this->GetGlobalGenerator()->IndexTarget(&it->second); + this->GetStateSnapshot().GetDirectory().AddNormalTargetName(name); return &it->second; } @@ -3709,10 +3711,10 @@ cmTarget* cmMakefile::AddImportedTarget(const std::string& name, cmState::TargetType type, bool global) { // Create the target. - CM_AUTO_PTR<cmTarget> target(new cmTarget); - target->SetType(type, name); - target->MarkAsImported(global); - target->SetMakefile(this); + CM_AUTO_PTR<cmTarget> target( + new cmTarget(name, type, global ? cmTarget::VisibilityImportedGlobally + : cmTarget::VisibilityImported, + this)); // Add to the set of available imported targets. this->ImportedTargets[name] = target.get(); diff --git a/Source/cmMakefileExecutableTargetGenerator.cxx b/Source/cmMakefileExecutableTargetGenerator.cxx index 66e1ca2..82bd1a3 100644 --- a/Source/cmMakefileExecutableTargetGenerator.cxx +++ b/Source/cmMakefileExecutableTargetGenerator.cxx @@ -138,14 +138,20 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( targetFullPathPDB, cmOutputConverter::SHELL); // Convert to the output path to use in constructing commands. - std::string targetOutPath = this->Convert( - targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - std::string targetOutPathReal = - this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath), + cmOutputConverter::SHELL); + std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + cmOutputConverter::SHELL); std::string targetOutPathImport = - this->Convert(targetFullPathImport, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathImport), + cmOutputConverter::SHELL); // Get the language to use for linking this executable. std::string linkLanguage = @@ -219,25 +225,27 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // may need to be cleaned. std::vector<std::string> exeCleanFiles; exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPath, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - (targetFullPath + ".manifest").c_str(), cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), + (targetFullPath + ".manifest").c_str())); #endif if (targetNameReal != targetName) { exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathReal, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal)); } if (!targetNameImport.empty()) { exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathImport, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathImport)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { exeCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - implib, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), implib)); } } @@ -245,7 +253,7 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) // cleaned. We do not want to delete the .pdb file just before // linking the target. this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathPDB, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB)); // Add the pre-build and pre-link rules building but not when relinking. if (!relink) { @@ -317,14 +325,19 @@ void cmMakefileExecutableTargetGenerator::WriteExecutableRule(bool relink) vars.Language = linkLanguage.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); - objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); vars.ObjectDir = objectDir.c_str(); cmOutputConverter::OutputFormat output = (useWatcomQuote) ? cmOutputConverter::WATCOMQUOTE : cmOutputConverter::SHELL; - std::string target = this->Convert( - targetFullPathReal, cmOutputConverter::START_OUTPUT, output); + std::string target = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + output); vars.Target = target.c_str(); vars.TargetPDB = targetOutPathPDB.c_str(); diff --git a/Source/cmMakefileLibraryTargetGenerator.cxx b/Source/cmMakefileLibraryTargetGenerator.cxx index c31c469..1d66d52 100644 --- a/Source/cmMakefileLibraryTargetGenerator.cxx +++ b/Source/cmMakefileLibraryTargetGenerator.cxx @@ -312,17 +312,25 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // arguments. std::string targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( targetFullPathPDB, cmOutputConverter::SHELL); - std::string targetOutPath = this->Convert( - targetFullPath, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); - std::string targetOutPathSO = - this->Convert(targetFullPathSO, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); - std::string targetOutPathReal = - this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + + std::string targetOutPath = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath), + cmOutputConverter::SHELL); + std::string targetOutPathSO = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO), + cmOutputConverter::SHELL); + std::string targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + cmOutputConverter::SHELL); std::string targetOutPathImport = - this->Convert(targetFullPathImport, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathImport), + cmOutputConverter::SHELL); this->NumberOfProgressActions++; if (!this->NoRuleMessages) { @@ -368,23 +376,24 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // Clean files associated with this library. std::vector<std::string> libCleanFiles; libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPath, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPath)); if (targetNameReal != targetName) { libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathReal, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal)); } if (targetNameSO != targetName && targetNameSO != targetNameReal) { libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathSO, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathSO)); } if (!targetNameImport.empty()) { libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathImport, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathImport)); std::string implib; if (this->GeneratorTarget->GetImplibGNUtoMS(targetFullPathImport, implib)) { libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - implib, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), implib)); } } @@ -392,15 +401,15 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( // cleaned. We do not want to delete the .pdb file just before // linking the target. this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - targetFullPathPDB, cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathPDB)); #ifdef _WIN32 // There may be a manifest file for this target. Add it to the // clean set just in case. if (this->GeneratorTarget->GetType() != cmState::STATIC_LIBRARY) { libCleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - (targetFullPath + ".manifest").c_str(), - cmOutputConverter::START_OUTPUT)); + this->LocalGenerator->GetCurrentBinaryDirectory(), + (targetFullPath + ".manifest").c_str())); } #endif @@ -535,14 +544,20 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules( vars.Language = linkLanguage.c_str(); vars.Objects = buildObjs.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); - objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); + vars.ObjectDir = objectDir.c_str(); cmOutputConverter::OutputFormat output = (useWatcomQuote) ? cmOutputConverter::WATCOMQUOTE : cmOutputConverter::SHELL; - std::string target = this->Convert( - targetFullPathReal, cmOutputConverter::START_OUTPUT, output); + std::string target = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + output); vars.Target = target.c_str(); vars.LinkLibraries = linkLibs.c_str(); vars.ObjectsQuoted = buildObjs.c_str(); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index 165f96c..e0d9fda 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -162,6 +162,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() // files for this target. std::vector<cmSourceFile const*> customCommands; this->GeneratorTarget->GetCustomCommands(customCommands, config); + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); for (std::vector<cmSourceFile const*>::const_iterator si = customCommands.begin(); si != customCommands.end(); ++si) { @@ -172,8 +174,8 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() const std::vector<std::string>& outputs = ccg.GetOutputs(); for (std::vector<std::string>::const_iterator o = outputs.begin(); o != outputs.end(); ++o) { - this->CleanFiles.push_back(this->LocalGenerator->ConvertToRelativePath( - *o, cmOutputConverter::START_OUTPUT)); + this->CleanFiles.push_back( + this->LocalGenerator->ConvertToRelativePath(currentBinDir, *o)); } } } @@ -214,8 +216,11 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() *this->BuildFileStream << "# Include any dependencies generated for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root - << this->Convert(dependFileNameFull, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->ConvertToRelativePath(this->LocalGenerator->GetBinaryDirectory(), + dependFileNameFull) + .c_str()) << "\n\n"; if (!this->NoRuleMessages) { @@ -223,9 +228,12 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() *this->BuildFileStream << "# Include the progress variables for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root - << this->Convert(this->ProgressFileNameFull, - cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->ConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull) + .c_str()) << "\n\n"; } @@ -255,8 +263,11 @@ void cmMakefileTargetGenerator::WriteCommonCodeRules() *this->BuildFileStream << "# Include the compile flags for this target's objects.\n" << this->GlobalGenerator->IncludeDirective << " " << root - << this->Convert(this->FlagFileNameFull, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->ConvertToRelativePath(this->LocalGenerator->GetBinaryDirectory(), + this->FlagFileNameFull) + .c_str()) << "\n\n"; } @@ -313,9 +324,9 @@ void cmMakefileTargetGenerator::MacOSXContentGeneratorType::operator()( output += cmSystemTools::GetFilenameName(input); this->Generator->CleanFiles.push_back( this->Generator->LocalGenerator->ConvertToRelativePath( - output, cmOutputConverter::START_OUTPUT)); + this->Generator->LocalGenerator->GetCurrentBinaryDirectory(), output)); output = this->Generator->LocalGenerator->ConvertToRelativePath( - output, cmOutputConverter::HOME_OUTPUT); + this->Generator->LocalGenerator->GetBinaryDirectory(), output); // Create a rule to copy the content into the bundle. std::vector<std::string> depends; @@ -515,14 +526,17 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( } } - targetOutPathReal = - this->Convert(targetFullPathReal, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + targetOutPathReal = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), targetFullPathReal), + cmOutputConverter::SHELL); targetOutPathPDB = this->LocalGenerator->ConvertToOutputFormat( targetFullPathPDB, cmOutputConverter::SHELL); - targetOutPathCompilePDB = - this->Convert(targetFullPathCompilePDB, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + targetOutPathCompilePDB = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), + targetFullPathCompilePDB), + cmOutputConverter::SHELL); if (this->LocalGenerator->IsMinGWMake() && cmHasLiteralSuffix(targetOutPathCompilePDB, "\\")) { @@ -544,12 +558,16 @@ void cmMakefileTargetGenerator::WriteObjectBuildFile( this->LocalGenerator->ConvertToOutputFormat(obj, cmOutputConverter::SHELL); vars.Object = shellObj.c_str(); std::string objectDir = this->GeneratorTarget->GetSupportDirectory(); - objectDir = this->Convert(objectDir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + objectDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectDir), + cmOutputConverter::SHELL); vars.ObjectDir = objectDir.c_str(); std::string objectFileDir = cmSystemTools::GetFilenamePath(obj); - objectFileDir = this->Convert(objectFileDir, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + objectFileDir = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objectFileDir), + cmOutputConverter::SHELL); vars.ObjectFileDir = objectFileDir.c_str(); vars.Flags = flags.c_str(); @@ -889,12 +907,14 @@ bool cmMakefileTargetGenerator::WriteMakeRule( // For multiple outputs, make the extra ones depend on the first one. std::vector<std::string> const output_depends(1, outputs[0]); + std::string binDir = this->LocalGenerator->GetBinaryDirectory(); for (std::vector<std::string>::const_iterator o = outputs.begin() + 1; o != outputs.end(); ++o) { // Touch the extra output so "make" knows that it was updated, // but only if the output was acually created. - std::string const out = this->Convert(*o, cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::SHELL); + std::string const out = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath(binDir, *o), + cmOutputConverter::SHELL); std::vector<std::string> output_commands; bool o_symbolic = false; @@ -973,12 +993,16 @@ void cmMakefileTargetGenerator::WriteTargetDependRules() *this->InfoFileStream << " )\n"; } + std::string const& working_dir = + this->LocalGenerator->GetCurrentBinaryDirectory(); + /* clang-format off */ *this->InfoFileStream << "\n" << "# Fortran module output directory.\n" << "set(CMAKE_Fortran_TARGET_MODULE_DIR \"" - << this->GeneratorTarget->GetFortranModuleDirectory() << "\")\n"; + << this->GeneratorTarget->GetFortranModuleDirectory(working_dir) + << "\")\n"; /* clang-format on */ // and now write the rule to use it @@ -1180,11 +1204,12 @@ void cmMakefileTargetGenerator::WriteObjectsVariable( << this->GeneratorTarget->GetName() << "\n" << variableNameExternal << " ="; /* clang-format on */ + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); for (std::vector<std::string>::const_iterator i = this->ExternalObjects.begin(); i != this->ExternalObjects.end(); ++i) { - object = this->LocalGenerator->ConvertToRelativePath( - *i, cmOutputConverter::START_OUTPUT); + object = this->LocalGenerator->ConvertToRelativePath(currentBinDir, *i); *this->BuildFileStream << " " << lineContinue << "\n" << this->Makefile->GetSafeDefinition( "CMAKE_OBJECT_NAME"); @@ -1217,8 +1242,10 @@ public: void Feed(std::string const& obj) { // Construct the name of the next object. - this->NextObject = this->LocalGenerator->Convert( - obj, cmOutputConverter::START_OUTPUT, cmOutputConverter::RESPONSE); + this->NextObject = this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), obj), + cmOutputConverter::RESPONSE); // Roll over to next string if the limit will be exceeded. if (this->LengthLimit != std::string::npos && @@ -1272,7 +1299,7 @@ void cmMakefileTargetGenerator::WriteTargetDriverRule( std::string buildTargetRuleName = dir; buildTargetRuleName += relink ? "/preinstall" : "/build"; buildTargetRuleName = this->LocalGenerator->ConvertToRelativePath( - buildTargetRuleName, cmOutputConverter::HOME_OUTPUT); + this->LocalGenerator->GetBinaryDirectory(), buildTargetRuleName); // Build the list of target outputs to drive. std::vector<std::string> depends; @@ -1460,8 +1487,10 @@ void cmMakefileTargetGenerator::CreateLinkScript( // Create the makefile command to invoke the link script. std::string link_command = "$(CMAKE_COMMAND) -E cmake_link_script "; - link_command += this->Convert( - linkScriptName, cmOutputConverter::START_OUTPUT, cmOutputConverter::SHELL); + link_command += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), linkScriptName), + cmOutputConverter::SHELL); link_command += " --verbose=$(VERBOSE)"; makefile_commands.push_back(link_command); makefile_depends.push_back(linkScriptName); @@ -1492,9 +1521,9 @@ bool cmMakefileTargetGenerator::CheckUseResponseFileForObjects( if (size_t const limit = calculateCommandLineLengthLimit()) { // Compute the total length of our list of object files with room // for argument separation and quoting. This does not convert paths - // relative to START_OUTPUT like the final list will be, so the actual - // list will likely be much shorter than this. However, in the worst - // case all objects will remain as absolute paths. + // relative to CMAKE_CURRENT_BINARY_DIR like the final list will be, so the + // actual list will likely be much shorter than this. However, in the + // worst case all objects will remain as absolute paths. size_t length = 0; for (std::vector<std::string>::const_iterator i = this->Objects.begin(); i != this->Objects.end(); ++i) { @@ -1695,13 +1724,17 @@ void cmMakefileTargetGenerator::GenDefFile( cmd = this->LocalGenerator->ConvertToOutputFormat( cmd, cmOutputConverter::SHELL); cmd += " -E __create_def "; - cmd += this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + cmd += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), name_of_def_file), + cmOutputConverter::SHELL); cmd += " "; std::string objlist_file = name_of_def_file; objlist_file += ".objs"; - cmd += this->Convert(objlist_file, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + cmd += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), objlist_file), + cmOutputConverter::SHELL); real_link_commands.insert(real_link_commands.begin(), cmd); // create a list of obj files for the -E __create_def to read cmGeneratedFileStream fout(objlist_file.c_str()); @@ -1719,9 +1752,10 @@ void cmMakefileTargetGenerator::GenDefFile( // now add the def file link flag linkFlags += " "; linkFlags += this->Makefile->GetSafeDefinition("CMAKE_LINK_DEF_FILE_FLAG"); - linkFlags += - this->Convert(name_of_def_file, cmOutputConverter::START_OUTPUT, - cmOutputConverter::SHELL); + linkFlags += this->LocalGenerator->ConvertToOutputFormat( + this->LocalGenerator->ConvertToRelativePath( + this->LocalGenerator->GetCurrentBinaryDirectory(), name_of_def_file), + cmOutputConverter::SHELL); linkFlags += " "; } } diff --git a/Source/cmMakefileUtilityTargetGenerator.cxx b/Source/cmMakefileUtilityTargetGenerator.cxx index b709545..8bf0a23 100644 --- a/Source/cmMakefileUtilityTargetGenerator.cxx +++ b/Source/cmMakefileUtilityTargetGenerator.cxx @@ -53,9 +53,12 @@ void cmMakefileUtilityTargetGenerator::WriteRuleFiles() *this->BuildFileStream << "# Include the progress variables for this target.\n" << this->GlobalGenerator->IncludeDirective << " " << root - << this->Convert(this->ProgressFileNameFull, - cmOutputConverter::HOME_OUTPUT, - cmOutputConverter::MAKERULE) + << cmSystemTools::ConvertToOutputPath( + this->LocalGenerator + ->ConvertToRelativePath( + this->LocalGenerator->GetBinaryDirectory(), + this->ProgressFileNameFull) + .c_str()) << "\n\n"; } diff --git a/Source/cmMarkAsAdvancedCommand.cxx b/Source/cmMarkAsAdvancedCommand.cxx index 2fb6a75..6c979f6 100644 --- a/Source/cmMarkAsAdvancedCommand.cxx +++ b/Source/cmMarkAsAdvancedCommand.cxx @@ -15,7 +15,7 @@ bool cmMarkAsAdvancedCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index ca8b926..b812349 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -16,7 +16,7 @@ bool cmMathCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("must be called with at least one argument."); return false; } diff --git a/Source/cmMessageCommand.cxx b/Source/cmMessageCommand.cxx index c48910e..e884531 100644 --- a/Source/cmMessageCommand.cxx +++ b/Source/cmMessageCommand.cxx @@ -17,7 +17,7 @@ bool cmMessageCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmNinjaNormalTargetGenerator.cxx b/Source/cmNinjaNormalTargetGenerator.cxx index 335b552..dbd84cb 100644 --- a/Source/cmNinjaNormalTargetGenerator.cxx +++ b/Source/cmNinjaNormalTargetGenerator.cxx @@ -336,7 +336,7 @@ std::vector<std::string> cmNinjaNormalTargetGenerator::ComputeLinkCmd() std::string targetOutputReal = this->ConvertToNinjaPath(gt.GetFullPath(cfgName, /*implib=*/false, - /*realpath=*/true)); + /*realname=*/true)); cmakeCommand += targetOutputReal; cmakeCommand += " || true"; linkCmds.push_back(cmakeCommand); @@ -414,7 +414,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() std::string targetOutputReal = ConvertToNinjaPath(gt.GetFullPath(cfgName, /*implib=*/false, - /*realpath=*/true)); + /*realname=*/true)); std::string targetOutputImplib = ConvertToNinjaPath(gt.GetFullPath(cfgName, /*implib=*/true)); @@ -642,7 +642,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() } } } - // If we have any PRE_LINK commands, we need to go back to HOME_OUTPUT for + // If we have any PRE_LINK commands, we need to go back to CMAKE_BINARY_DIR + // for // the link commands. if (!preLinkCmdLines.empty()) { const std::string homeOutDir = localGen.ConvertToOutputFormat( @@ -690,7 +691,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() // Write the build statement for this target. bool usedResponseFile = false; globalGen.WriteBuild(this->GetBuildFileStream(), comment.str(), - this->LanguageLinkerRule(), outputs, explicitDeps, + this->LanguageLinkerRule(), outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, vars, rspfile, commandLineLengthLimit, &usedResponseFile); this->WriteLinkRule(usedResponseFile); @@ -701,7 +703,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() this->GetBuildFileStream(), "Create executable symlink " + targetOutput, "CMAKE_SYMLINK_EXECUTABLE", cmNinjaDeps(1, targetOutput), - cmNinjaDeps(1, targetOutputReal), emptyDeps, emptyDeps, symlinkVars); + /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), + emptyDeps, emptyDeps, symlinkVars); } else { cmNinjaDeps symlinks; std::string const soName = @@ -716,7 +719,8 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement() symlinks.push_back(targetOutput); globalGen.WriteBuild( this->GetBuildFileStream(), "Create library symlink " + targetOutput, - "CMAKE_SYMLINK_LIBRARY", symlinks, cmNinjaDeps(1, targetOutputReal), + "CMAKE_SYMLINK_LIBRARY", symlinks, + /*implicitOuts=*/cmNinjaDeps(), cmNinjaDeps(1, targetOutputReal), emptyDeps, emptyDeps, symlinkVars); } } diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 6ac59d5..fb09bfe 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -607,8 +607,9 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string const rspfile = objectFileName + ".rsp"; this->GetGlobalGenerator()->WriteBuild( - this->GetBuildFileStream(), comment, rule, outputs, explicitDeps, - implicitDeps, orderOnlyDeps, vars, rspfile, commandLineLengthLimit); + this->GetBuildFileStream(), comment, rule, outputs, + /*implicitOuts=*/cmNinjaDeps(), explicitDeps, implicitDeps, orderOnlyDeps, + vars, rspfile, commandLineLengthLimit); if (const char* objectOutputs = source->GetProperty("OBJECT_OUTPUTS")) { std::vector<std::string> outputList; diff --git a/Source/cmOutputConverter.cxx b/Source/cmOutputConverter.cxx index d44fbb7..7f6edf2 100644 --- a/Source/cmOutputConverter.cxx +++ b/Source/cmOutputConverter.cxx @@ -46,51 +46,12 @@ std::string cmOutputConverter::ConvertToOutputForExisting( return this->ConvertToOutputFormat(remote, format); } -std::string cmOutputConverter::ConvertToRelativePath( - const std::string& source, RelativeRoot relative) const -{ - std::string result; - - switch (relative) { - case HOME: - result = this->ConvertToRelativePath( - this->GetState()->GetSourceDirectoryComponents(), source); - break; - case START: - result = this->ConvertToRelativePath( - this->StateSnapshot.GetDirectory().GetCurrentSourceComponents(), - source); - break; - case HOME_OUTPUT: - result = this->ConvertToRelativePath( - this->GetState()->GetBinaryDirectoryComponents(), source); - break; - case START_OUTPUT: - result = this->ConvertToRelativePath( - this->StateSnapshot.GetDirectory().GetCurrentBinaryComponents(), - source); - break; - } - return result; -} - -std::string cmOutputConverter::Convert(const std::string& source, - RelativeRoot relative, - OutputFormat output) const -{ - // Convert the path to a relative path. - std::string result = this->ConvertToRelativePath(source, relative); - return this->ConvertToOutputFormat(result, output); -} - std::string cmOutputConverter::ConvertToOutputFormat(const std::string& source, OutputFormat output) const { std::string result = source; // Convert it to an output path. - if (output == MAKERULE) { - result = cmSystemTools::ConvertToOutputPath(result.c_str()); - } else if (output == SHELL || output == WATCOMQUOTE) { + if (output == SHELL || output == WATCOMQUOTE) { result = this->ConvertDirectorySeparatorsForShell(source); result = this->EscapeForShell(result, true, false, output == WATCOMQUOTE); } else if (output == RESPONSE) { @@ -128,41 +89,67 @@ std::string cmOutputConverter::ConvertToRelativePath( const std::vector<std::string>& local, const std::string& in_remote, bool force) const { - // The path should never be quoted. - assert(in_remote[0] != '\"'); + std::string local_path = cmSystemTools::JoinPath(local); + return force ? this->ForceToRelativePath(local_path, in_remote) + : this->ConvertToRelativePath(local_path, in_remote); +} + +std::string cmOutputConverter::ConvertToRelativePath( + std::string const& local_path, std::string const& remote_path) const +{ + // The paths should never be quoted. + assert(local_path[0] != '\"'); + assert(remote_path[0] != '\"'); // The local path should never have a trailing slash. - assert(!local.empty() && !(local[local.size() - 1] == "")); + assert(local_path.empty() || local_path[local_path.size() - 1] != '/'); // If the path is already relative then just return the path. - if (!cmSystemTools::FileIsFullPath(in_remote.c_str())) { - return in_remote; - } - - if (!force) { - // Skip conversion if the path and local are not both in the source - // or both in the binary tree. - std::string local_path = cmSystemTools::JoinPath(local); - if (!((cmOutputConverterNotAbove( - local_path.c_str(), - this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()) && - cmOutputConverterNotAbove( - in_remote.c_str(), - this->StateSnapshot.GetDirectory().GetRelativePathTopBinary())) || - (cmOutputConverterNotAbove( - local_path.c_str(), - this->StateSnapshot.GetDirectory().GetRelativePathTopSource()) && - cmOutputConverterNotAbove(in_remote.c_str(), - this->StateSnapshot.GetDirectory() - .GetRelativePathTopSource())))) { - return in_remote; - } + if (!cmSystemTools::FileIsFullPath(remote_path.c_str())) { + return remote_path; + } + + // Skip conversion if the path and local are not both in the source + // or both in the binary tree. + if (!((cmOutputConverterNotAbove( + local_path.c_str(), + this->StateSnapshot.GetDirectory().GetRelativePathTopBinary()) && + cmOutputConverterNotAbove( + remote_path.c_str(), + this->StateSnapshot.GetDirectory().GetRelativePathTopBinary())) || + (cmOutputConverterNotAbove( + local_path.c_str(), + this->StateSnapshot.GetDirectory().GetRelativePathTopSource()) && + cmOutputConverterNotAbove( + remote_path.c_str(), + this->StateSnapshot.GetDirectory().GetRelativePathTopSource())))) { + return remote_path; + } + + return this->ForceToRelativePath(local_path, remote_path); +} + +std::string cmOutputConverter::ForceToRelativePath( + std::string const& local_path, std::string const& remote_path) +{ + // The paths should never be quoted. + assert(local_path[0] != '\"'); + assert(remote_path[0] != '\"'); + + // The local path should never have a trailing slash. + assert(local_path.empty() || local_path[local_path.size() - 1] != '/'); + + // If the path is already relative then just return the path. + if (!cmSystemTools::FileIsFullPath(remote_path.c_str())) { + return remote_path; } // Identify the longest shared path component between the remote // path and the local path. + std::vector<std::string> local; + cmSystemTools::SplitPath(local_path, local); std::vector<std::string> remote; - cmSystemTools::SplitPath(in_remote, remote); + cmSystemTools::SplitPath(remote_path, remote); unsigned int common = 0; while (common < remote.size() && common < local.size() && cmSystemTools::ComparePath(remote[common], local[common])) { @@ -171,7 +158,7 @@ std::string cmOutputConverter::ConvertToRelativePath( // If no part of the path is in common then return the full path. if (common == 0) { - return in_remote; + return remote_path; } // If the entire path is in common then just return a ".". diff --git a/Source/cmOutputConverter.h b/Source/cmOutputConverter.h index ac58ddc..cc24e53 100644 --- a/Source/cmOutputConverter.h +++ b/Source/cmOutputConverter.h @@ -24,40 +24,14 @@ class cmOutputConverter public: cmOutputConverter(cmState::Snapshot snapshot); - /** - * Convert something to something else. This is a centralized conversion - * routine used by the generators to handle relative paths and the like. - * The flags determine what is actually done. - * - * relative: treat the argument as a directory and convert it to make it - * relative or full or unchanged. If relative (HOME, START etc) then that - * specifies what it should be relative to. - * - * output: make the result suitable for output to a... - * - * optional: should any relative path operation be controlled by the rel - * path setting - */ - enum RelativeRoot - { - HOME, - START, - HOME_OUTPUT, - START_OUTPUT - }; enum OutputFormat { - MAKERULE, SHELL, WATCOMQUOTE, RESPONSE }; std::string ConvertToOutputFormat(const std::string& source, OutputFormat output) const; - std::string Convert(const std::string& remote, RelativeRoot local, - OutputFormat output) const; - std::string ConvertToRelativePath(const std::string& remote, - RelativeRoot local) const; std::string ConvertDirectorySeparatorsForShell( const std::string& source) const; @@ -145,6 +119,24 @@ public: const std::string& in_remote, bool force = false) const; + /** + * Convert the given remote path to a relative path with respect to + * the given local path. Both paths must use forward slashes and not + * already be escaped or quoted. + * The conversion is skipped if the paths are not both in the source + * or both in the binary tree. + */ + std::string ConvertToRelativePath(std::string const& local_path, + std::string const& remote_path) const; + + /** + * Convert the given remote path to a relative path with respect to + * the given local path. Both paths must use forward slashes and not + * already be escaped or quoted. + */ + static std::string ForceToRelativePath(std::string const& local_path, + std::string const& remote_path); + private: cmState* GetState() const; diff --git a/Source/cmOutputRequiredFilesCommand.cxx b/Source/cmOutputRequiredFilesCommand.cxx index ef636e7..730ce6d 100644 --- a/Source/cmOutputRequiredFilesCommand.cxx +++ b/Source/cmOutputRequiredFilesCommand.cxx @@ -307,10 +307,10 @@ protected: // If dependencies are already done, stop now. if (info->DependDone) { return; - } else { - // Make sure we don't visit the same file more than once. - info->DependDone = true; } + // Make sure we don't visit the same file more than once. + info->DependDone = true; + const char* path = info->FullPath.c_str(); if (!path) { cmSystemTools::Error( @@ -405,15 +405,14 @@ protected: if (result != this->DependInformationMap.end()) { // Found an instance, return it. return result->second; - } else { - // Didn't find an instance. Create a new one and save it. - cmDependInformation* info = new cmDependInformation; - info->FullPath = fullPath; - info->PathOnly = cmSystemTools::GetFilenamePath(fullPath); - info->IncludeName = file; - this->DependInformationMap[fullPath] = info; - return info; } + // Didn't find an instance. Create a new one and save it. + cmDependInformation* info = new cmDependInformation; + info->FullPath = fullPath; + info->PathOnly = cmSystemTools::GetFilenamePath(fullPath); + info->IncludeName = file; + this->DependInformationMap[fullPath] = info; + return info; } /** diff --git a/Source/cmProjectCommand.cxx b/Source/cmProjectCommand.cxx index 139303b..6f98d94 100644 --- a/Source/cmProjectCommand.cxx +++ b/Source/cmProjectCommand.cxx @@ -15,7 +15,7 @@ bool cmProjectCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("PROJECT called with incorrect number of arguments"); return false; } diff --git a/Source/cmRemoveCommand.cxx b/Source/cmRemoveCommand.cxx index 955f712..c695374 100644 --- a/Source/cmRemoveCommand.cxx +++ b/Source/cmRemoveCommand.cxx @@ -15,7 +15,7 @@ bool cmRemoveCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmRemoveDefinitionsCommand.cxx b/Source/cmRemoveDefinitionsCommand.cxx index 638eda6..77de846 100644 --- a/Source/cmRemoveDefinitionsCommand.cxx +++ b/Source/cmRemoveDefinitionsCommand.cxx @@ -16,7 +16,7 @@ bool cmRemoveDefinitionsCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { // it is OK to have no arguments - if (args.size() < 1) { + if (args.empty()) { return true; } diff --git a/Source/cmSearchPath.cxx b/Source/cmSearchPath.cxx index ca3a57f..46498e6 100644 --- a/Source/cmSearchPath.cxx +++ b/Source/cmSearchPath.cxx @@ -124,9 +124,8 @@ static std::string cmSearchPathStripBin(std::string const& s) // If the path is a PREFIX/bin case then add its parent instead. if ((cmHasLiteralSuffix(s, "/bin")) || (cmHasLiteralSuffix(s, "/sbin"))) { return cmSystemTools::GetFilenamePath(s); - } else { - return s; } + return s; } void cmSearchPath::AddEnvPrefixPath(const std::string& variable, bool stripBin) diff --git a/Source/cmServer.cxx b/Source/cmServer.cxx new file mode 100644 index 0000000..be001a7 --- /dev/null +++ b/Source/cmServer.cxx @@ -0,0 +1,473 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2015 Stephen Kelly <steveire@gmail.com> + Copyright 2016 Tobias Hunger <tobias.hunger@qt.io> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmServer.h" + +#include "cmServerProtocol.h" +#include "cmSystemTools.h" +#include "cmVersionMacros.h" +#include "cmake.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_reader.h" +#include "cm_jsoncpp_value.h" +#endif + +#include <fstream> +#include <iostream> +#include <memory> + +static const std::string kTYPE_KEY = "type"; +static const std::string kCOOKIE_KEY = "cookie"; +static const std::string kREPLY_TO_KEY = "inReplyTo"; +static const std::string kERROR_MESSAGE_KEY = "errorMessage"; + +static const std::string kERROR_TYPE = "error"; +static const std::string kREPLY_TYPE = "reply"; +static const std::string kPROGRESS_TYPE = "progress"; +static const std::string kMESSAGE_TYPE = "message"; + +static const std::string kSTART_MAGIC = "[== CMake Server ==["; +static const std::string kEND_MAGIC = "]== CMake Server ==]"; + +typedef struct +{ + uv_write_t req; + uv_buf_t buf; +} write_req_t; + +void alloc_buffer(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) +{ + (void)handle; + *buf = uv_buf_init(static_cast<char*>(malloc(suggested_size)), + static_cast<unsigned int>(suggested_size)); +} + +void free_write_req(uv_write_t* req) +{ + write_req_t* wr = reinterpret_cast<write_req_t*>(req); + free(wr->buf.base); + free(wr); +} + +void on_stdout_write(uv_write_t* req, int status) +{ + (void)status; + auto server = reinterpret_cast<cmServer*>(req->data); + free_write_req(req); + server->PopOne(); +} + +void write_data(uv_stream_t* dest, std::string content, uv_write_cb cb) +{ + write_req_t* req = static_cast<write_req_t*>(malloc(sizeof(write_req_t))); + req->req.data = dest->data; + req->buf = uv_buf_init(static_cast<char*>(malloc(content.size())), + static_cast<unsigned int>(content.size())); + memcpy(req->buf.base, content.c_str(), content.size()); + uv_write(reinterpret_cast<uv_write_t*>(req), static_cast<uv_stream_t*>(dest), + &req->buf, 1, cb); +} + +void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) +{ + if (nread > 0) { + auto server = reinterpret_cast<cmServer*>(stream->data); + std::string result = std::string(buf->base, buf->base + nread); + server->handleData(result); + } + + if (buf->base) + free(buf->base); +} + +class cmServer::DebugInfo +{ +public: + DebugInfo() + : StartTime(uv_hrtime()) + { + } + + bool PrintStatistics = false; + + std::string OutputFile; + uint64_t StartTime; +}; + +cmServer::cmServer(bool supportExperimental) + : SupportExperimental(supportExperimental) +{ + // Register supported protocols: + this->RegisterProtocol(new cmServerProtocol1_0); +} + +cmServer::~cmServer() +{ + if (!this->Protocol) { // Server was never fully started! + return; + } + + uv_close(reinterpret_cast<uv_handle_t*>(this->InputStream), NULL); + uv_close(reinterpret_cast<uv_handle_t*>(this->OutputStream), NULL); + uv_loop_close(this->Loop); + + for (cmServerProtocol* p : this->SupportedProtocols) { + delete p; + } +} + +void cmServer::PopOne() +{ + this->Writing = false; + if (this->Queue.empty()) { + return; + } + + Json::Reader reader; + Json::Value value; + const std::string input = this->Queue.front(); + this->Queue.erase(this->Queue.begin()); + + if (!reader.parse(input, value)) { + this->WriteParseError("Failed to parse JSON input."); + return; + } + + std::unique_ptr<DebugInfo> debug; + Json::Value debugValue = value["debug"]; + if (!debugValue.isNull()) { + debug = std::make_unique<DebugInfo>(); + debug->OutputFile = debugValue["dumpToFile"].asString(); + debug->PrintStatistics = debugValue["showStats"].asBool(); + } + + const cmServerRequest request(this, value[kTYPE_KEY].asString(), + value[kCOOKIE_KEY].asString(), value); + + if (request.Type == "") { + cmServerResponse response(request); + response.SetError("No type given in request."); + this->WriteResponse(response, nullptr); + return; + } + + cmSystemTools::SetMessageCallback(reportMessage, + const_cast<cmServerRequest*>(&request)); + if (this->Protocol) { + this->Protocol->CMakeInstance()->SetProgressCallback( + reportProgress, const_cast<cmServerRequest*>(&request)); + this->WriteResponse(this->Protocol->Process(request), debug.get()); + } else { + this->WriteResponse(this->SetProtocolVersion(request), debug.get()); + } +} + +void cmServer::handleData(const std::string& data) +{ + this->DataBuffer += data; + + for (;;) { + auto needle = this->DataBuffer.find('\n'); + + if (needle == std::string::npos) { + return; + } + std::string line = this->DataBuffer.substr(0, needle); + const auto ls = line.size(); + if (ls > 1 && line.at(ls - 1) == '\r') + line.erase(ls - 1, 1); + this->DataBuffer.erase(this->DataBuffer.begin(), + this->DataBuffer.begin() + needle + 1); + if (line == kSTART_MAGIC) { + this->JsonData.clear(); + continue; + } + if (line == kEND_MAGIC) { + this->Queue.push_back(this->JsonData); + this->JsonData.clear(); + if (!this->Writing) { + this->PopOne(); + } + } else { + this->JsonData += line; + this->JsonData += "\n"; + } + } +} + +void cmServer::RegisterProtocol(cmServerProtocol* protocol) +{ + if (protocol->IsExperimental() && !this->SupportExperimental) { + return; + } + auto version = protocol->ProtocolVersion(); + assert(version.first >= 0); + assert(version.second >= 0); + auto it = std::find_if(this->SupportedProtocols.begin(), + this->SupportedProtocols.end(), + [version](cmServerProtocol* p) { + return p->ProtocolVersion() == version; + }); + if (it == this->SupportedProtocols.end()) + this->SupportedProtocols.push_back(protocol); +} + +void cmServer::PrintHello() const +{ + Json::Value hello = Json::objectValue; + hello[kTYPE_KEY] = "hello"; + + Json::Value& protocolVersions = hello["supportedProtocolVersions"] = + Json::arrayValue; + + for (auto const& proto : this->SupportedProtocols) { + auto version = proto->ProtocolVersion(); + Json::Value tmp = Json::objectValue; + tmp["major"] = version.first; + tmp["minor"] = version.second; + if (proto->IsExperimental()) { + tmp["experimental"] = true; + } + protocolVersions.append(tmp); + } + + this->WriteJsonObject(hello, nullptr); +} + +void cmServer::reportProgress(const char* msg, float progress, void* data) +{ + const cmServerRequest* request = static_cast<const cmServerRequest*>(data); + assert(request); + if (progress < 0.0 || progress > 1.0) { + request->ReportMessage(msg, ""); + } else { + request->ReportProgress(0, static_cast<int>(progress * 1000), 1000, msg); + } +} + +void cmServer::reportMessage(const char* msg, const char* title, + bool& /* cancel */, void* data) +{ + const cmServerRequest* request = static_cast<const cmServerRequest*>(data); + assert(request); + assert(msg); + std::string titleString; + if (title) { + titleString = title; + } + request->ReportMessage(std::string(msg), titleString); +} + +cmServerResponse cmServer::SetProtocolVersion(const cmServerRequest& request) +{ + if (request.Type != "handshake") + return request.ReportError("Waiting for type \"handshake\"."); + + Json::Value requestedProtocolVersion = request.Data["protocolVersion"]; + if (requestedProtocolVersion.isNull()) + return request.ReportError( + "\"protocolVersion\" is required for \"handshake\"."); + + if (!requestedProtocolVersion.isObject()) + return request.ReportError("\"protocolVersion\" must be a JSON object."); + + Json::Value majorValue = requestedProtocolVersion["major"]; + if (!majorValue.isInt()) + return request.ReportError("\"major\" must be set and an integer."); + + Json::Value minorValue = requestedProtocolVersion["minor"]; + if (!minorValue.isNull() && !minorValue.isInt()) + return request.ReportError("\"minor\" must be unset or an integer."); + + const int major = majorValue.asInt(); + const int minor = minorValue.isNull() ? -1 : minorValue.asInt(); + if (major < 0) + return request.ReportError("\"major\" must be >= 0."); + if (!minorValue.isNull() && minor < 0) + return request.ReportError("\"minor\" must be >= 0 when set."); + + this->Protocol = + this->FindMatchingProtocol(this->SupportedProtocols, major, minor); + if (!this->Protocol) { + return request.ReportError("Protocol version not supported."); + } + + std::string errorMessage; + if (!this->Protocol->Activate(request, &errorMessage)) { + this->Protocol = CM_NULLPTR; + return request.ReportError("Failed to activate protocol version: " + + errorMessage); + } + return request.Reply(Json::objectValue); +} + +bool cmServer::Serve() +{ + if (this->SupportedProtocols.empty()) { + return false; + } + assert(!this->Protocol); + + this->Loop = uv_default_loop(); + + if (uv_guess_handle(1) == UV_TTY) { + uv_tty_init(this->Loop, &this->Input.tty, 0, 1); + uv_tty_set_mode(&this->Input.tty, UV_TTY_MODE_NORMAL); + this->Input.tty.data = this; + InputStream = reinterpret_cast<uv_stream_t*>(&this->Input.tty); + + uv_tty_init(this->Loop, &this->Output.tty, 1, 0); + uv_tty_set_mode(&this->Output.tty, UV_TTY_MODE_NORMAL); + this->Output.tty.data = this; + OutputStream = reinterpret_cast<uv_stream_t*>(&this->Output.tty); + } else { + uv_pipe_init(this->Loop, &this->Input.pipe, 0); + uv_pipe_open(&this->Input.pipe, 0); + this->Input.pipe.data = this; + InputStream = reinterpret_cast<uv_stream_t*>(&this->Input.pipe); + + uv_pipe_init(this->Loop, &this->Output.pipe, 0); + uv_pipe_open(&this->Output.pipe, 1); + this->Output.pipe.data = this; + OutputStream = reinterpret_cast<uv_stream_t*>(&this->Output.pipe); + } + + this->PrintHello(); + + uv_read_start(this->InputStream, alloc_buffer, read_stdin); + + uv_run(this->Loop, UV_RUN_DEFAULT); + return true; +} + +void cmServer::WriteJsonObject(const Json::Value& jsonValue, + const DebugInfo* debug) const +{ + Json::FastWriter writer; + + auto beforeJson = uv_hrtime(); + std::string result = writer.write(jsonValue); + + if (debug) { + Json::Value copy = jsonValue; + if (debug->PrintStatistics) { + Json::Value stats = Json::objectValue; + auto endTime = uv_hrtime(); + + stats["jsonSerialization"] = double(endTime - beforeJson) / 1000000.0; + stats["totalTime"] = double(endTime - debug->StartTime) / 1000000.0; + stats["size"] = static_cast<int>(result.size()); + if (!debug->OutputFile.empty()) { + stats["dumpFile"] = debug->OutputFile; + } + + copy["zzzDebug"] = stats; + + result = writer.write(copy); // Update result to include debug info + } + + if (!debug->OutputFile.empty()) { + std::ofstream myfile; + myfile.open(debug->OutputFile); + myfile << result; + myfile.close(); + } + } + + this->Writing = true; + write_data(this->OutputStream, std::string("\n") + kSTART_MAGIC + + std::string("\n") + result + kEND_MAGIC + std::string("\n"), + on_stdout_write); +} + +cmServerProtocol* cmServer::FindMatchingProtocol( + const std::vector<cmServerProtocol*>& protocols, int major, int minor) +{ + cmServerProtocol* bestMatch = nullptr; + for (auto protocol : protocols) { + auto version = protocol->ProtocolVersion(); + if (major != version.first) + continue; + if (minor == version.second) + return protocol; + if (!bestMatch || bestMatch->ProtocolVersion().second < version.second) + bestMatch = protocol; + } + return minor < 0 ? bestMatch : nullptr; +} + +void cmServer::WriteProgress(const cmServerRequest& request, int min, + int current, int max, + const std::string& message) const +{ + assert(min <= current && current <= max); + assert(message.length() != 0); + + Json::Value obj = Json::objectValue; + obj[kTYPE_KEY] = kPROGRESS_TYPE; + obj[kREPLY_TO_KEY] = request.Type; + obj[kCOOKIE_KEY] = request.Cookie; + obj["progressMessage"] = message; + obj["progressMinimum"] = min; + obj["progressMaximum"] = max; + obj["progressCurrent"] = current; + + this->WriteJsonObject(obj, nullptr); +} + +void cmServer::WriteMessage(const cmServerRequest& request, + const std::string& message, + const std::string& title) const +{ + if (message.empty()) + return; + + Json::Value obj = Json::objectValue; + obj[kTYPE_KEY] = kMESSAGE_TYPE; + obj[kREPLY_TO_KEY] = request.Type; + obj[kCOOKIE_KEY] = request.Cookie; + obj["message"] = message; + if (!title.empty()) { + obj["title"] = title; + } + + WriteJsonObject(obj, nullptr); +} + +void cmServer::WriteParseError(const std::string& message) const +{ + Json::Value obj = Json::objectValue; + obj[kTYPE_KEY] = kERROR_TYPE; + obj[kERROR_MESSAGE_KEY] = message; + obj[kREPLY_TO_KEY] = ""; + obj[kCOOKIE_KEY] = ""; + + this->WriteJsonObject(obj, nullptr); +} + +void cmServer::WriteResponse(const cmServerResponse& response, + const DebugInfo* debug) const +{ + assert(response.IsComplete()); + + Json::Value obj = response.Data(); + obj[kCOOKIE_KEY] = response.Cookie; + obj[kTYPE_KEY] = response.IsError() ? kERROR_TYPE : kREPLY_TYPE; + obj[kREPLY_TO_KEY] = response.Type; + if (response.IsError()) { + obj[kERROR_MESSAGE_KEY] = response.ErrorMessage(); + } + + this->WriteJsonObject(obj, debug); +} diff --git a/Source/cmServer.h b/Source/cmServer.h new file mode 100644 index 0000000..38a11bb --- /dev/null +++ b/Source/cmServer.h @@ -0,0 +1,97 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2015 Stephen Kelly <steveire@gmail.com> + Copyright 2016 Tobias Hunger <tobias.hunger@qt.io> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#pragma once + +#include "cmListFileCache.h" +#include "cmState.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_value.h" +#include "cm_uv.h" +#endif + +#include <string> +#include <vector> + +class cmServerProtocol; +class cmServerRequest; +class cmServerResponse; + +class cmServer +{ +public: + class DebugInfo; + + cmServer(bool supportExperimental); + ~cmServer(); + + bool Serve(); + + // for callbacks: + void PopOne(); + void handleData(std::string const& data); + +private: + void RegisterProtocol(cmServerProtocol* protocol); + + static void reportProgress(const char* msg, float progress, void* data); + static void reportMessage(const char* msg, const char* title, bool& cancel, + void* data); + + // Handle requests: + cmServerResponse SetProtocolVersion(const cmServerRequest& request); + + void PrintHello() const; + + // Write responses: + void WriteProgress(const cmServerRequest& request, int min, int current, + int max, const std::string& message) const; + void WriteMessage(const cmServerRequest& request, const std::string& message, + const std::string& title) const; + void WriteResponse(const cmServerResponse& response, + const DebugInfo* debug) const; + void WriteParseError(const std::string& message) const; + + void WriteJsonObject(Json::Value const& jsonValue, + const DebugInfo* debug) const; + + static cmServerProtocol* FindMatchingProtocol( + const std::vector<cmServerProtocol*>& protocols, int major, int minor); + + const bool SupportExperimental; + + cmServerProtocol* Protocol = nullptr; + std::vector<cmServerProtocol*> SupportedProtocols; + std::vector<std::string> Queue; + + std::string DataBuffer; + std::string JsonData; + + uv_loop_t* Loop = nullptr; + + typedef union + { + uv_tty_t tty; + uv_pipe_t pipe; + } InOutUnion; + + InOutUnion Input; + InOutUnion Output; + uv_stream_t* InputStream = nullptr; + uv_stream_t* OutputStream = nullptr; + + mutable bool Writing = false; + + friend class cmServerRequest; +}; diff --git a/Source/cmServerProtocol.cxx b/Source/cmServerProtocol.cxx new file mode 100644 index 0000000..26942d3 --- /dev/null +++ b/Source/cmServerProtocol.cxx @@ -0,0 +1,272 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Tobias Hunger <tobias.hunger@qt.io> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#include "cmServerProtocol.h" + +#include "cmExternalMakefileProjectGenerator.h" +#include "cmServer.h" +#include "cmSystemTools.h" +#include "cmake.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_reader.h" +#include "cm_jsoncpp_value.h" +#endif + +// Vocabulary: + +static const std::string kBUILD_DIRECTORY_KEY = "buildDirectory"; +static const std::string kCOOKIE_KEY = "cookie"; +static const std::string kEXTRA_GENERATOR_KEY = "extraGenerator"; +static const std::string kGENERATOR_KEY = "generator"; +static const std::string kSOURCE_DIRECTORY_KEY = "sourceDirectory"; +static const std::string kTYPE_KEY = "type"; + +cmServerRequest::cmServerRequest(cmServer* server, const std::string& t, + const std::string& c, const Json::Value& d) + : Type(t) + , Cookie(c) + , Data(d) + , m_Server(server) +{ +} + +void cmServerRequest::ReportProgress(int min, int current, int max, + const std::string& message) const +{ + this->m_Server->WriteProgress(*this, min, current, max, message); +} + +void cmServerRequest::ReportMessage(const std::string& message, + const std::string& title) const +{ + m_Server->WriteMessage(*this, message, title); +} + +cmServerResponse cmServerRequest::Reply(const Json::Value& data) const +{ + cmServerResponse response(*this); + response.SetData(data); + return response; +} + +cmServerResponse cmServerRequest::ReportError(const std::string& message) const +{ + cmServerResponse response(*this); + response.SetError(message); + return response; +} + +cmServerResponse::cmServerResponse(const cmServerRequest& request) + : Type(request.Type) + , Cookie(request.Cookie) +{ +} + +void cmServerResponse::SetData(const Json::Value& data) +{ + assert(this->m_Payload == PAYLOAD_UNKNOWN); + if (!data[kCOOKIE_KEY].isNull() || !data[kTYPE_KEY].isNull()) { + this->SetError("Response contains cookie or type field."); + return; + } + this->m_Payload = PAYLOAD_DATA; + this->m_Data = data; +} + +void cmServerResponse::SetError(const std::string& message) +{ + assert(this->m_Payload == PAYLOAD_UNKNOWN); + this->m_Payload = PAYLOAD_ERROR; + this->m_ErrorMessage = message; +} + +bool cmServerResponse::IsComplete() const +{ + return this->m_Payload != PAYLOAD_UNKNOWN; +} + +bool cmServerResponse::IsError() const +{ + assert(this->m_Payload != PAYLOAD_UNKNOWN); + return this->m_Payload == PAYLOAD_ERROR; +} + +std::string cmServerResponse::ErrorMessage() const +{ + if (this->m_Payload == PAYLOAD_ERROR) + return this->m_ErrorMessage; + else + return std::string(); +} + +Json::Value cmServerResponse::Data() const +{ + assert(this->m_Payload != PAYLOAD_UNKNOWN); + return this->m_Data; +} + +bool cmServerProtocol::Activate(const cmServerRequest& request, + std::string* errorMessage) +{ + this->m_CMakeInstance = std::make_unique<cmake>(); + const bool result = this->DoActivate(request, errorMessage); + if (!result) + this->m_CMakeInstance = CM_NULLPTR; + return result; +} + +cmake* cmServerProtocol::CMakeInstance() const +{ + return this->m_CMakeInstance.get(); +} + +bool cmServerProtocol::DoActivate(const cmServerRequest& /*request*/, + std::string* /*errorMessage*/) +{ + return true; +} + +std::pair<int, int> cmServerProtocol1_0::ProtocolVersion() const +{ + return std::make_pair(1, 0); +} + +bool cmServerProtocol1_0::DoActivate(const cmServerRequest& request, + std::string* errorMessage) +{ + std::string sourceDirectory = request.Data[kSOURCE_DIRECTORY_KEY].asString(); + const std::string buildDirectory = + request.Data[kBUILD_DIRECTORY_KEY].asString(); + std::string generator = request.Data[kGENERATOR_KEY].asString(); + std::string extraGenerator = request.Data[kEXTRA_GENERATOR_KEY].asString(); + + if (buildDirectory.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kBUILD_DIRECTORY_KEY + "\" is missing."; + return false; + } + cmake* cm = CMakeInstance(); + if (cmSystemTools::PathExists(buildDirectory)) { + if (!cmSystemTools::FileIsDirectory(buildDirectory)) { + if (errorMessage) + *errorMessage = std::string("\"") + kBUILD_DIRECTORY_KEY + + "\" exists but is not a directory."; + return false; + } + + const std::string cachePath = cm->FindCacheFile(buildDirectory); + if (cm->LoadCache(cachePath)) { + cmState* state = cm->GetState(); + + // Check generator: + const std::string cachedGenerator = + std::string(state->GetCacheEntryValue("CMAKE_GENERATOR")); + if (cachedGenerator.empty() && generator.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kGENERATOR_KEY + "\" is required but unset."; + return false; + } + if (generator.empty()) { + generator = cachedGenerator; + } + if (generator != cachedGenerator) { + if (errorMessage) + *errorMessage = std::string("\"") + kGENERATOR_KEY + + "\" set but incompatible with configured generator."; + return false; + } + + // check extra generator: + const std::string cachedExtraGenerator = + std::string(state->GetCacheEntryValue("CMAKE_EXTRA_GENERATOR")); + if (!cachedExtraGenerator.empty() && !extraGenerator.empty() && + cachedExtraGenerator != extraGenerator) { + if (errorMessage) + *errorMessage = std::string("\"") + kEXTRA_GENERATOR_KEY + + "\" is set but incompatible with configured extra generator."; + return false; + } + if (extraGenerator.empty()) { + extraGenerator = cachedExtraGenerator; + } + + // check sourcedir: + const std::string cachedSourceDirectory = + std::string(state->GetCacheEntryValue("CMAKE_HOME_DIRECTORY")); + if (!cachedSourceDirectory.empty() && !sourceDirectory.empty() && + cachedSourceDirectory != sourceDirectory) { + if (errorMessage) + *errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY + + "\" is set but incompatible with configured source directory."; + return false; + } + if (sourceDirectory.empty()) { + sourceDirectory = cachedSourceDirectory; + } + } + } + + if (sourceDirectory.empty()) { + if (errorMessage) + *errorMessage = std::string("\"") + kSOURCE_DIRECTORY_KEY + + "\" is unset but required."; + return false; + } + if (!cmSystemTools::FileIsDirectory(sourceDirectory)) { + if (errorMessage) + *errorMessage = + std::string("\"") + kSOURCE_DIRECTORY_KEY + "\" is not a directory."; + return false; + } + if (generator.empty()) { + if (errorMessage) + *errorMessage = + std::string("\"") + kGENERATOR_KEY + "\" is unset but required."; + return false; + } + + const std::string fullGeneratorName = + cmExternalMakefileProjectGenerator::CreateFullGeneratorName( + generator, extraGenerator); + + cmGlobalGenerator* gg = cm->CreateGlobalGenerator(fullGeneratorName); + if (!gg) { + if (errorMessage) + *errorMessage = + std::string("Could not set up the requested combination of \"") + + kGENERATOR_KEY + "\" and \"" + kEXTRA_GENERATOR_KEY + "\""; + return false; + } + + cm->SetGlobalGenerator(gg); + cm->SetHomeDirectory(sourceDirectory); + cm->SetHomeOutputDirectory(buildDirectory); + + this->m_State = STATE_ACTIVE; + return true; +} + +const cmServerResponse cmServerProtocol1_0::Process( + const cmServerRequest& request) +{ + assert(this->m_State >= STATE_ACTIVE); + + return request.ReportError("Unknown command!"); +} + +bool cmServerProtocol1_0::IsExperimental() const +{ + return true; +} diff --git a/Source/cmServerProtocol.h b/Source/cmServerProtocol.h new file mode 100644 index 0000000..bab949b --- /dev/null +++ b/Source/cmServerProtocol.h @@ -0,0 +1,121 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2016 Tobias Hunger <tobias.hunger@qt.io> + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ + +#pragma once + +#include "cmListFileCache.h" + +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_writer.h" +#endif + +#include <memory> +#include <string> + +class cmake; +class cmServer; + +class cmServerRequest; + +class cmServerResponse +{ +public: + explicit cmServerResponse(const cmServerRequest& request); + + void SetData(const Json::Value& data); + void SetError(const std::string& message); + + bool IsComplete() const; + bool IsError() const; + std::string ErrorMessage() const; + Json::Value Data() const; + + const std::string Type; + const std::string Cookie; + +private: + enum PayLoad + { + PAYLOAD_UNKNOWN, + PAYLOAD_ERROR, + PAYLOAD_DATA + }; + PayLoad m_Payload = PAYLOAD_UNKNOWN; + std::string m_ErrorMessage; + Json::Value m_Data; +}; + +class cmServerRequest +{ +public: + cmServerResponse Reply(const Json::Value& data) const; + cmServerResponse ReportError(const std::string& message) const; + + const std::string Type; + const std::string Cookie; + const Json::Value Data; + +private: + cmServerRequest(cmServer* server, const std::string& t, const std::string& c, + const Json::Value& d); + + void ReportProgress(int min, int current, int max, + const std::string& message) const; + void ReportMessage(const std::string& message, + const std::string& title) const; + + cmServer* m_Server; + + friend class cmServer; +}; + +class cmServerProtocol +{ +public: + virtual ~cmServerProtocol() {} + + virtual std::pair<int, int> ProtocolVersion() const = 0; + virtual bool IsExperimental() const = 0; + virtual const cmServerResponse Process(const cmServerRequest& request) = 0; + + bool Activate(const cmServerRequest& request, std::string* errorMessage); + +protected: + cmake* CMakeInstance() const; + // Implement protocol specific activation tasks here. Called from Activate(). + virtual bool DoActivate(const cmServerRequest& request, + std::string* errorMessage); + +private: + std::unique_ptr<cmake> m_CMakeInstance; + + friend class cmServer; +}; + +class cmServerProtocol1_0 : public cmServerProtocol +{ +public: + std::pair<int, int> ProtocolVersion() const override; + bool IsExperimental() const override; + const cmServerResponse Process(const cmServerRequest& request) override; + +private: + bool DoActivate(const cmServerRequest& request, + std::string* errorMessage) override; + + enum State + { + STATE_INACTIVE, + STATE_ACTIVE + }; + State m_State = STATE_INACTIVE; +}; diff --git a/Source/cmSetCommand.cxx b/Source/cmSetCommand.cxx index 8fb6aa0..0660b76 100644 --- a/Source/cmSetCommand.cxx +++ b/Source/cmSetCommand.cxx @@ -15,7 +15,7 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -59,7 +59,7 @@ bool cmSetCommand::InitialPass(std::vector<std::string> const& args, } // SET (VAR PARENT_SCOPE) // Removes the definition of VAR // in the parent scope. - else if (args.size() == 2 && args[args.size() - 1] == "PARENT_SCOPE") { + if (args.size() == 2 && args[args.size() - 1] == "PARENT_SCOPE") { this->Makefile->RaiseScope(variable, CM_NULLPTR); return true; } diff --git a/Source/cmSetDirectoryPropertiesCommand.cxx b/Source/cmSetDirectoryPropertiesCommand.cxx index ca758da..03b195a 100644 --- a/Source/cmSetDirectoryPropertiesCommand.cxx +++ b/Source/cmSetDirectoryPropertiesCommand.cxx @@ -17,7 +17,7 @@ bool cmSetDirectoryPropertiesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -45,7 +45,8 @@ bool cmSetDirectoryPropertiesCommand::RunCommand( if (prop == "VARIABLES") { errors = "Variables and cache variables should be set using SET command"; return false; - } else if (prop == "MACROS") { + } + if (prop == "MACROS") { errors = "Commands and macros cannot be set using SET_CMAKE_PROPERTIES"; return false; } diff --git a/Source/cmSetTestsPropertiesCommand.cxx b/Source/cmSetTestsPropertiesCommand.cxx index 2fb137f..59d569d 100644 --- a/Source/cmSetTestsPropertiesCommand.cxx +++ b/Source/cmSetTestsPropertiesCommand.cxx @@ -18,7 +18,7 @@ bool cmSetTestsPropertiesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmSourceGroupCommand.cxx b/Source/cmSourceGroupCommand.cxx index 6db14c0..6f7ef6c 100644 --- a/Source/cmSourceGroupCommand.cxx +++ b/Source/cmSourceGroupCommand.cxx @@ -15,7 +15,7 @@ bool cmSourceGroupCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmState.cxx b/Source/cmState.cxx index 073c239..6b37b92 100644 --- a/Source/cmState.cxx +++ b/Source/cmState.cxx @@ -29,6 +29,11 @@ #include <string.h> #include <utility> +static std::string const kBINARY_DIR = "BINARY_DIR"; +static std::string const kBUILDSYSTEM_TARGETS = "BUILDSYSTEM_TARGETS"; +static std::string const kSOURCE_DIR = "SOURCE_DIR"; +static std::string const kSUBDIRECTORIES = "SUBDIRECTORIES"; + struct cmState::SnapshotDataType { cmState::PositionType ScopeParent; @@ -77,8 +82,6 @@ struct cmState::BuildsystemDirectoryStateType std::string Location; std::string OutputLocation; - std::vector<std::string> CurrentSourceDirectoryComponents; - std::vector<std::string> CurrentBinaryDirectoryComponents; // The top-most directories for relative path conversion. Both the // source and destination location of a relative path conversion // must be underneath one of these directories (both under source or @@ -96,6 +99,8 @@ struct cmState::BuildsystemDirectoryStateType std::vector<std::string> CompileOptions; std::vector<cmListFileBacktrace> CompileOptionsBacktraces; + std::vector<std::string> NormalTargetNames; + std::string ProjectName; cmPropertyMap Properties; @@ -326,6 +331,7 @@ cmState::Snapshot cmState::Reset() it->CompileOptions.clear(); it->CompileOptionsBacktraces.clear(); it->DirectoryEnd = pos; + it->NormalTargetNames.clear(); it->Properties.clear(); it->Children.clear(); } @@ -591,10 +597,6 @@ void cmState::SetSourceDirectory(std::string const& sourceDirectory) { this->SourceDirectory = sourceDirectory; cmSystemTools::ConvertToUnixSlashes(this->SourceDirectory); - - cmSystemTools::SplitPath( - cmSystemTools::CollapseFullPath(this->SourceDirectory), - this->SourceDirectoryComponents); } const char* cmState::GetSourceDirectory() const @@ -602,19 +604,10 @@ const char* cmState::GetSourceDirectory() const return this->SourceDirectory.c_str(); } -std::vector<std::string> const& cmState::GetSourceDirectoryComponents() const -{ - return this->SourceDirectoryComponents; -} - void cmState::SetBinaryDirectory(std::string const& binaryDirectory) { this->BinaryDirectory = binaryDirectory; cmSystemTools::ConvertToUnixSlashes(this->BinaryDirectory); - - cmSystemTools::SplitPath( - cmSystemTools::CollapseFullPath(this->BinaryDirectory), - this->BinaryDirectoryComponents); } void cmState::SetWindowsShell(bool windowsShell) @@ -692,11 +685,6 @@ const char* cmState::GetBinaryDirectory() const return this->BinaryDirectory.c_str(); } -std::vector<std::string> const& cmState::GetBinaryDirectoryComponents() const -{ - return this->BinaryDirectoryComponents; -} - void cmState::Directory::ComputeRelativePathTopSource() { // Relative path conversion inside the source tree is not used to @@ -978,8 +966,6 @@ void cmState::Directory::SetCurrentSource(std::string const& dir) cmSystemTools::ConvertToUnixSlashes(loc); loc = cmSystemTools::CollapseFullPath(loc); - cmSystemTools::SplitPath( - loc, this->DirectoryState->CurrentSourceDirectoryComponents); this->ComputeRelativePathTopSource(); this->Snapshot_.SetDefinition("CMAKE_CURRENT_SOURCE_DIR", loc); @@ -997,8 +983,6 @@ void cmState::Directory::SetCurrentBinary(std::string const& dir) cmSystemTools::ConvertToUnixSlashes(loc); loc = cmSystemTools::CollapseFullPath(loc); - cmSystemTools::SplitPath( - loc, this->DirectoryState->CurrentBinaryDirectoryComponents); this->ComputeRelativePathTopBinary(); this->Snapshot_.SetDefinition("CMAKE_CURRENT_BINARY_DIR", loc); @@ -1009,18 +993,6 @@ void cmState::Snapshot::SetListFile(const std::string& listfile) *this->Position->ExecutionListFile = listfile; } -std::vector<std::string> const& -cmState::Directory::GetCurrentSourceComponents() const -{ - return this->DirectoryState->CurrentSourceDirectoryComponents; -} - -std::vector<std::string> const& -cmState::Directory::GetCurrentBinaryComponents() const -{ - return this->DirectoryState->CurrentBinaryDirectoryComponents; -} - const char* cmState::Directory::GetRelativePathTopSource() const { return this->DirectoryState->RelativePathTopSource.c_str(); @@ -1703,6 +1675,30 @@ const char* cmState::Directory::GetProperty(const std::string& prop, } return ""; } + if (prop == kBINARY_DIR) { + output = this->GetCurrentBinary(); + return output.c_str(); + } + if (prop == kSOURCE_DIR) { + output = this->GetCurrentSource(); + return output.c_str(); + } + if (prop == kSUBDIRECTORIES) { + std::vector<std::string> child_dirs; + std::vector<cmState::Snapshot> const& children = + this->DirectoryState->Children; + for (std::vector<cmState::Snapshot>::const_iterator ci = children.begin(); + ci != children.end(); ++ci) { + child_dirs.push_back(ci->GetDirectory().GetCurrentSource()); + } + output = cmJoin(child_dirs, ";"); + return output.c_str(); + } + if (prop == kBUILDSYSTEM_TARGETS) { + output = cmJoin(this->DirectoryState->NormalTargetNames, ";"); + return output.c_str(); + } + if (prop == "LISTFILE_STACK") { std::vector<std::string> listFiles; cmState::Snapshot snp = this->Snapshot_; @@ -1769,6 +1765,11 @@ std::vector<std::string> cmState::Directory::GetPropertyKeys() const return keys; } +void cmState::Directory::AddNormalTargetName(std::string const& name) +{ + this->DirectoryState->NormalTargetNames.push_back(name); +} + bool operator==(const cmState::Snapshot& lhs, const cmState::Snapshot& rhs) { return lhs.Position == rhs.Position; diff --git a/Source/cmState.h b/Source/cmState.h index 9ab4213..1324f5f 100644 --- a/Source/cmState.h +++ b/Source/cmState.h @@ -135,9 +135,6 @@ public: const char* GetCurrentBinary() const; void SetCurrentBinary(std::string const& dir); - std::vector<std::string> const& GetCurrentSourceComponents() const; - std::vector<std::string> const& GetCurrentBinaryComponents() const; - const char* GetRelativePathTopSource() const; const char* GetRelativePathTopBinary() const; void SetRelativePathTopSource(const char* dir); @@ -178,6 +175,8 @@ public: bool GetPropertyAsBool(const std::string& prop) const; std::vector<std::string> GetPropertyKeys() const; + void AddNormalTargetName(std::string const& name); + private: void ComputeRelativePathTopSource(); void ComputeRelativePathTopBinary(); @@ -312,9 +311,6 @@ public: const char* GetBinaryDirectory() const; void SetBinaryDirectory(std::string const& binaryDirectory); - std::vector<std::string> const& GetSourceDirectoryComponents() const; - std::vector<std::string> const& GetBinaryDirectoryComponents() const; - void SetWindowsShell(bool windowsShell); bool UseWindowsShell() const; void SetWindowsVSIDE(bool windowsVSIDE); @@ -350,8 +346,6 @@ private: cmLinkedTree<SnapshotDataType> SnapshotData; cmLinkedTree<cmDefinitions> VarTree; - std::vector<std::string> SourceDirectoryComponents; - std::vector<std::string> BinaryDirectoryComponents; std::string SourceDirectory; std::string BinaryDirectory; bool IsInTryCompile; diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 3c913ee..cfb537f 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -26,7 +26,7 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("must be called with at least one argument."); return false; } @@ -34,43 +34,61 @@ bool cmStringCommand::InitialPass(std::vector<std::string> const& args, const std::string& subCommand = args[0]; if (subCommand == "REGEX") { return this->HandleRegexCommand(args); - } else if (subCommand == "REPLACE") { + } + if (subCommand == "REPLACE") { return this->HandleReplaceCommand(args); - } else if (subCommand == "MD5" || subCommand == "SHA1" || - subCommand == "SHA224" || subCommand == "SHA256" || - subCommand == "SHA384" || subCommand == "SHA512") { + } + if (subCommand == "MD5" || subCommand == "SHA1" || subCommand == "SHA224" || + subCommand == "SHA256" || subCommand == "SHA384" || + subCommand == "SHA512") { return this->HandleHashCommand(args); - } else if (subCommand == "TOLOWER") { + } + if (subCommand == "TOLOWER") { return this->HandleToUpperLowerCommand(args, false); - } else if (subCommand == "TOUPPER") { + } + if (subCommand == "TOUPPER") { return this->HandleToUpperLowerCommand(args, true); - } else if (subCommand == "COMPARE") { + } + if (subCommand == "COMPARE") { return this->HandleCompareCommand(args); - } else if (subCommand == "ASCII") { + } + if (subCommand == "ASCII") { return this->HandleAsciiCommand(args); - } else if (subCommand == "CONFIGURE") { + } + if (subCommand == "CONFIGURE") { return this->HandleConfigureCommand(args); - } else if (subCommand == "LENGTH") { + } + if (subCommand == "LENGTH") { return this->HandleLengthCommand(args); - } else if (subCommand == "APPEND") { + } + if (subCommand == "APPEND") { return this->HandleAppendCommand(args); - } else if (subCommand == "CONCAT") { + } + if (subCommand == "CONCAT") { return this->HandleConcatCommand(args); - } else if (subCommand == "SUBSTRING") { + } + if (subCommand == "SUBSTRING") { return this->HandleSubstringCommand(args); - } else if (subCommand == "STRIP") { + } + if (subCommand == "STRIP") { return this->HandleStripCommand(args); - } else if (subCommand == "RANDOM") { + } + if (subCommand == "RANDOM") { return this->HandleRandomCommand(args); - } else if (subCommand == "FIND") { + } + if (subCommand == "FIND") { return this->HandleFindCommand(args); - } else if (subCommand == "TIMESTAMP") { + } + if (subCommand == "TIMESTAMP") { return this->HandleTimestampCommand(args); - } else if (subCommand == "MAKE_C_IDENTIFIER") { + } + if (subCommand == "MAKE_C_IDENTIFIER") { return this->HandleMakeCIdentifierCommand(args); - } else if (subCommand == "GENEX_STRIP") { + } + if (subCommand == "GENEX_STRIP") { return this->HandleGenexStripCommand(args); - } else if (subCommand == "UUID") { + } + if (subCommand == "UUID") { return this->HandleUuidCommand(args); } @@ -158,7 +176,8 @@ bool cmStringCommand::HandleConfigureCommand( if (args.size() < 2) { this->SetError("No input string specified."); return false; - } else if (args.size() < 3) { + } + if (args.size() < 3) { this->SetError("No output variable specified."); return false; } @@ -203,14 +222,16 @@ bool cmStringCommand::HandleRegexCommand(std::vector<std::string> const& args) return false; } return this->RegexMatch(args); - } else if (mode == "MATCHALL") { + } + if (mode == "MATCHALL") { if (args.size() < 5) { this->SetError("sub-command REGEX, mode MATCHALL needs " "at least 5 arguments total to command."); return false; } return this->RegexMatchAll(args); - } else if (mode == "REPLACE") { + } + if (mode == "REPLACE") { if (args.size() < 6) { this->SetError("sub-command REGEX, mode REPLACE needs " "at least 6 arguments total to command."); @@ -785,7 +806,8 @@ bool cmStringCommand::HandleTimestampCommand( if (args.size() < 2) { this->SetError("sub-command TIMESTAMP requires at least one argument."); return false; - } else if (args.size() > 4) { + } + if (args.size() > 4) { this->SetError("sub-command TIMESTAMP takes at most three arguments."); return false; } diff --git a/Source/cmSubdirCommand.cxx b/Source/cmSubdirCommand.cxx index 401f588..4893978 100644 --- a/Source/cmSubdirCommand.cxx +++ b/Source/cmSubdirCommand.cxx @@ -15,7 +15,7 @@ bool cmSubdirCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index 7352217..36ed614 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -2416,6 +2416,83 @@ bool cmSystemTools::VersionCompareGreaterEq(std::string const& lhs, lhs.c_str(), rhs.c_str()); } +static size_t cm_strverscmp_find_first_difference_or_end(const char* lhs, + const char* rhs) +{ + size_t i = 0; + /* Step forward until we find a difference or both strings end together. + The difference may lie on the null-terminator of one string. */ + while (lhs[i] == rhs[i] && lhs[i] != 0) { + ++i; + } + return i; +} + +static size_t cm_strverscmp_find_digits_begin(const char* s, size_t i) +{ + /* Step back until we are not preceded by a digit. */ + while (i > 0 && isdigit(s[i - 1])) { + --i; + } + return i; +} + +static size_t cm_strverscmp_find_digits_end(const char* s, size_t i) +{ + /* Step forward over digits. */ + while (isdigit(s[i])) { + ++i; + } + return i; +} + +static size_t cm_strverscmp_count_leading_zeros(const char* s, size_t b) +{ + size_t i = b; + /* Step forward over zeros that are followed by another digit. */ + while (s[i] == '0' && isdigit(s[i + 1])) { + ++i; + } + return i - b; +} + +static int cm_strverscmp(const char* lhs, const char* rhs) +{ + size_t const i = cm_strverscmp_find_first_difference_or_end(lhs, rhs); + if (lhs[i] != rhs[i]) { + /* The strings differ starting at 'i'. Check for a digit sequence. */ + size_t const b = cm_strverscmp_find_digits_begin(lhs, i); + if (b != i || (isdigit(lhs[i]) && isdigit(rhs[i]))) { + /* A digit sequence starts at 'b', preceding or at 'i'. */ + + /* Look for leading zeros, implying a leading decimal point. */ + size_t const lhs_zeros = cm_strverscmp_count_leading_zeros(lhs, b); + size_t const rhs_zeros = cm_strverscmp_count_leading_zeros(rhs, b); + if (lhs_zeros != rhs_zeros) { + /* The side with more leading zeros orders first. */ + return rhs_zeros > lhs_zeros ? 1 : -1; + } + if (lhs_zeros == 0) { + /* No leading zeros; compare digit sequence lengths. */ + size_t const lhs_end = cm_strverscmp_find_digits_end(lhs, i); + size_t const rhs_end = cm_strverscmp_find_digits_end(rhs, i); + if (lhs_end != rhs_end) { + /* The side with fewer digits orders first. */ + return lhs_end > rhs_end ? 1 : -1; + } + } + } + } + + /* Ordering was not decided by digit sequence lengths; compare bytes. */ + return lhs[i] - rhs[i]; +} + +int cmSystemTools::strverscmp(std::string const& lhs, std::string const& rhs) +{ + return cm_strverscmp(lhs.c_str(), rhs.c_str()); +} + bool cmSystemTools::RemoveRPath(std::string const& file, std::string* emsg, bool* removed) { diff --git a/Source/cmSystemTools.h b/Source/cmSystemTools.h index 3c1a9f4..aecf40e 100644 --- a/Source/cmSystemTools.h +++ b/Source/cmSystemTools.h @@ -306,6 +306,16 @@ public: std::string const& rhs); /** + * Compare two ASCII strings using natural versioning order. + * Non-numerical characters are compared directly. + * Numerical characters are first globbed such that, e.g. + * `test000 < test01 < test0 < test1 < test10`. + * Return a value less than, equal to, or greater than zero if lhs + * precedes, equals, or succeeds rhs in the defined ordering. + */ + static int strverscmp(std::string const& lhs, std::string const& rhs); + + /** * Determine the file type based on the extension */ static FileFormat GetFileFormat(const char* ext); diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index d5274cd..1dad742 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -59,34 +59,28 @@ public: std::vector<cmListFileBacktrace> LinkImplementationPropertyBacktraces; }; -cmTarget::cmTarget() +cmTarget::cmTarget(std::string const& name, cmState::TargetType type, + Visibility vis, cmMakefile* mf) { - this->Makefile = CM_NULLPTR; + assert(mf); + this->Name = name; + this->TargetTypeValue = type; + this->Makefile = mf; this->HaveInstallRule = false; this->DLLPlatform = false; this->IsAndroid = false; - this->IsImportedTarget = false; - this->ImportedGloballyVisible = false; + this->IsImportedTarget = + (vis == VisibilityImported || vis == VisibilityImportedGlobally); + this->ImportedGloballyVisible = vis == VisibilityImportedGlobally; this->BuildInterfaceIncludesAppended = false; -} -void cmTarget::SetType(cmState::TargetType type, const std::string& name) -{ - this->Name = name; // only add dependency information for library targets - this->TargetTypeValue = type; if (this->TargetTypeValue >= cmState::STATIC_LIBRARY && this->TargetTypeValue <= cmState::MODULE_LIBRARY) { this->RecordDependencies = true; } else { this->RecordDependencies = false; } -} - -void cmTarget::SetMakefile(cmMakefile* mf) -{ - // Set our makefile. - this->Makefile = mf; // Check whether this is a DLL platform. this->DLLPlatform = @@ -602,8 +596,8 @@ void cmTarget::GetTllSignatureTraces(std::ostream& s, TLLSignature sig) const it != this->TLLCommands.end(); ++it) { if (it->first == sig) { cmListFileContext lfc = it->second; - lfc.FilePath = - converter.ConvertToRelativePath(lfc.FilePath, cmOutputConverter::HOME); + lfc.FilePath = converter.ConvertToRelativePath( + this->Makefile->GetState()->GetSourceDirectory(), lfc.FilePath); s << " * " << lfc << std::endl; } } @@ -1062,12 +1056,6 @@ void cmTarget::CheckProperty(const std::string& prop, } } -void cmTarget::MarkAsImported(bool global) -{ - this->IsImportedTarget = true; - this->ImportedGloballyVisible = global; -} - bool cmTarget::HandleLocationPropertyPolicy(cmMakefile* context) const { if (this->IsImported()) { diff --git a/Source/cmTarget.h b/Source/cmTarget.h index fc30166..4b182bb 100644 --- a/Source/cmTarget.h +++ b/Source/cmTarget.h @@ -63,7 +63,16 @@ private: class cmTarget { public: - cmTarget(); + enum Visibility + { + VisibilityNormal, + VisibilityImported, + VisibilityImportedGlobally + }; + + cmTarget(std::string const& name, cmState::TargetType type, Visibility vis, + cmMakefile* mf); + enum CustomCommandType { PRE_BUILD, @@ -76,18 +85,10 @@ public: */ cmState::TargetType GetType() const { return this->TargetTypeValue; } - /** - * Set the target type - */ - void SetType(cmState::TargetType f, const std::string& name); - - void MarkAsImported(bool global = false); - ///! Set/Get the name of the target const std::string& GetName() const { return this->Name; } - ///! Set the cmMakefile that owns this target - void SetMakefile(cmMakefile* mf); + /** Get the cmMakefile that owns this target. */ cmMakefile* GetMakefile() const { return this->Makefile; } #define DECLARE_TARGET_POLICY(POLICY) \ diff --git a/Source/cmTargetLinkLibrariesCommand.cxx b/Source/cmTargetLinkLibrariesCommand.cxx index 1c4a9ce..950db16 100644 --- a/Source/cmTargetLinkLibrariesCommand.cxx +++ b/Source/cmTargetLinkLibrariesCommand.cxx @@ -22,7 +22,7 @@ bool cmTargetLinkLibrariesCommand::InitialPass( std::vector<std::string> const& args, cmExecutionStatus&) { // must have one argument - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } @@ -353,10 +353,9 @@ bool cmTargetLinkLibrariesCommand::HandleLibrary(const std::string& lib, "INTERFACE_LINK_LIBRARIES", this->Target->GetDebugGeneratorExpressions(lib, llt).c_str()); return true; - } else if (this->CurrentProcessingState != - ProcessingKeywordPublicInterface && - this->CurrentProcessingState != - ProcessingPlainPublicInterface) { + } + if (this->CurrentProcessingState != ProcessingKeywordPublicInterface && + this->CurrentProcessingState != ProcessingPlainPublicInterface) { if (this->Target->GetType() == cmState::STATIC_LIBRARY) { std::string configLib = this->Target->GetDebugGeneratorExpressions(lib, llt); diff --git a/Source/cmTimestamp.cxx b/Source/cmTimestamp.cxx index 61b74db..a94212c 100644 --- a/Source/cmTimestamp.cxx +++ b/Source/cmTimestamp.cxx @@ -123,6 +123,8 @@ std::string cmTimestamp::AddTimestampComponent(char flag, formatString += flag; switch (flag) { + case 'a': + case 'b': case 'd': case 'H': case 'I': diff --git a/Source/cmUnsetCommand.cxx b/Source/cmUnsetCommand.cxx index 05ba65a..874015d 100644 --- a/Source/cmUnsetCommand.cxx +++ b/Source/cmUnsetCommand.cxx @@ -15,7 +15,7 @@ bool cmUnsetCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1 || args.size() > 2) { + if (args.empty() || args.size() > 2) { this->SetError("called with incorrect number of arguments"); return false; } @@ -36,23 +36,21 @@ bool cmUnsetCommand::InitialPass(std::vector<std::string> const& args, return true; } // unset(VAR) - else if (args.size() == 1) { + if (args.size() == 1) { this->Makefile->RemoveDefinition(variable); return true; } // unset(VAR CACHE) - else if ((args.size() == 2) && (args[1] == "CACHE")) { + if ((args.size() == 2) && (args[1] == "CACHE")) { this->Makefile->RemoveCacheDefinition(variable); return true; } // unset(VAR PARENT_SCOPE) - else if ((args.size() == 2) && (args[1] == "PARENT_SCOPE")) { + if ((args.size() == 2) && (args[1] == "PARENT_SCOPE")) { this->Makefile->RaiseScope(variable, CM_NULLPTR); return true; } // ERROR: second argument isn't CACHE or PARENT_SCOPE - else { - this->SetError("called with an invalid second argument"); - return false; - } + this->SetError("called with an invalid second argument"); + return false; } diff --git a/Source/cmVariableWatchCommand.cxx b/Source/cmVariableWatchCommand.cxx index f30ffe8..cf740db 100644 --- a/Source/cmVariableWatchCommand.cxx +++ b/Source/cmVariableWatchCommand.cxx @@ -104,7 +104,7 @@ cmVariableWatchCommand::~cmVariableWatchCommand() bool cmVariableWatchCommand::InitialPass(std::vector<std::string> const& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("must be called with at least one argument."); return false; } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 8ff7366..85084eb 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -2415,10 +2415,12 @@ void cmVisualStudio10TargetGenerator::AddLibraries( { typedef cmComputeLinkInformation::ItemVector ItemVector; ItemVector libs = cli.GetItems(); + std::string currentBinDir = + this->LocalGenerator->GetCurrentBinaryDirectory(); for (ItemVector::const_iterator l = libs.begin(); l != libs.end(); ++l) { if (l->IsPath) { std::string path = this->LocalGenerator->ConvertToRelativePath( - l->Value.c_str(), cmOutputConverter::START_OUTPUT); + currentBinDir, l->Value.c_str()); this->ConvertToWindowsSlash(path); libVec.push_back(path); } else if (!l->Target || diff --git a/Source/cmWhileCommand.cxx b/Source/cmWhileCommand.cxx index 93a6271..98bd3ff 100644 --- a/Source/cmWhileCommand.cxx +++ b/Source/cmWhileCommand.cxx @@ -104,10 +104,9 @@ bool cmWhileFunctionBlocker::IsFunctionBlocked(const cmListFileFunction& lff, messageType); } return true; - } else { - // decrement for each nested while that ends - this->Depth--; } + // decrement for each nested while that ends + this->Depth--; } // record the command @@ -133,7 +132,7 @@ bool cmWhileFunctionBlocker::ShouldRemove(const cmListFileFunction& lff, bool cmWhileCommand::InvokeInitialPass( const std::vector<cmListFileArgument>& args, cmExecutionStatus&) { - if (args.size() < 1) { + if (args.empty()) { this->SetError("called with incorrect number of arguments"); return false; } diff --git a/Source/cm_auto_ptr.hxx b/Source/cm_auto_ptr.hxx index 2cd35c3..f6c4362 100644 --- a/Source/cm_auto_ptr.hxx +++ b/Source/cm_auto_ptr.hxx @@ -12,7 +12,7 @@ #ifndef CM_AUTO_PTR_HXX #define CM_AUTO_PTR_HXX -#include <cmsys/Configure.hxx> +#include <cmConfigure.h> // FIXME: Use std::auto_ptr on compilers that do not warn about it. #define CM_AUTO_PTR cm::auto_ptr @@ -115,7 +115,7 @@ public: * * auto_ptr<X> ptr(new X()); */ - explicit auto_ptr(X* p = 0) throw() + explicit auto_ptr(X* p = CM_NULLPTR) throw() : x_(p) { } @@ -157,7 +157,7 @@ public: X* release() throw() { X* x = this->x_; - this->x_ = 0; + this->x_ = CM_NULLPTR; return x; } diff --git a/Source/cmake.cxx b/Source/cmake.cxx index d6bea3d..0c84283 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -35,7 +35,7 @@ #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cmGraphVizWriter.h" #include "cmVariableWatch.h" -#include <cm_jsoncpp_value.h> + #include <cm_jsoncpp_writer.h> #endif @@ -233,10 +233,9 @@ cmake::~cmake() delete this->FileComparison; } -std::string cmake::ReportCapabilities() const -{ - std::string result; #if defined(CMAKE_BUILD_WITH_CMAKE) +Json::Value cmake::ReportCapabilitiesJson(bool haveServerMode) const +{ Json::Value obj = Json::objectValue; // Version information: Json::Value version = Json::objectValue; @@ -281,14 +280,18 @@ std::string cmake::ReportCapabilities() const generators.append(i->second); } obj["generators"] = generators; + obj["serverMode"] = haveServerMode; -#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE - obj["serverMode"] = true; -#else - obj["serverMode"] = false; + return obj; +} #endif + +std::string cmake::ReportCapabilities(bool haveServerMode) const +{ + std::string result; +#if defined(CMAKE_BUILD_WITH_CMAKE) Json::FastWriter writer; - result = writer.write(obj); + result = writer.write(this->ReportCapabilitiesJson(haveServerMode)); #else result = "Not supported"; #endif @@ -588,8 +591,8 @@ bool cmake::FindPackage(const std::vector<std::string>& args) gg->CreateGenerationObjects(); cmGeneratorTarget* gtgt = gg->FindGeneratorTarget(tgt->GetName()); cmLocalGenerator* lg = gtgt->GetLocalGenerator(); - lg->GetTargetFlags(buildType, linkLibs, frameworkPath, linkPath, flags, - linkFlags, gtgt, false); + lg->GetTargetFlags(buildType, linkLibs, flags, linkFlags, frameworkPath, + linkPath, gtgt, false); linkLibs = frameworkPath + linkPath + linkLibs; printf("%s\n", linkLibs.c_str()); @@ -1039,6 +1042,28 @@ const char* cmake::GetHomeOutputDirectory() const return this->State->GetBinaryDirectory(); } +std::string cmake::FindCacheFile(const std::string& binaryDir) +{ + std::string cachePath = binaryDir; + cmSystemTools::ConvertToUnixSlashes(cachePath); + std::string cacheFile = cachePath; + cacheFile += "/CMakeCache.txt"; + if (!cmSystemTools::FileExists(cacheFile.c_str())) { + // search in parent directories for cache + std::string cmakeFiles = cachePath; + cmakeFiles += "/CMakeFiles"; + if (cmSystemTools::FileExists(cmakeFiles.c_str())) { + std::string cachePathFound = + cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt", + cachePath.c_str(), "/"); + if (!cachePathFound.empty()) { + cachePath = cmSystemTools::GetFilenamePath(cachePathFound); + } + } + } + return cachePath; +} + void cmake::SetGlobalGenerator(cmGlobalGenerator* gg) { if (!gg) { @@ -2337,24 +2362,8 @@ int cmake::Build(const std::string& dir, const std::string& target, std::cerr << "Error: " << dir << " is not a directory\n"; return 1; } - std::string cachePath = dir; - cmSystemTools::ConvertToUnixSlashes(cachePath); - std::string cacheFile = cachePath; - cacheFile += "/CMakeCache.txt"; - if (!cmSystemTools::FileExists(cacheFile.c_str())) { - // search in parent directories for cache - std::string cmakeFiles = cachePath; - cmakeFiles += "/CMakeFiles"; - if (cmSystemTools::FileExists(cmakeFiles.c_str())) { - std::string cachePathFound = - cmSystemTools::FileExistsInParentDirectories("CMakeCache.txt", - cachePath.c_str(), "/"); - if (!cachePathFound.empty()) { - cachePath = cmSystemTools::GetFilenamePath(cachePathFound); - } - } - } + std::string cachePath = FindCacheFile(dir); if (!this->LoadCache(cachePath)) { std::cerr << "Error: could not load cache\n"; return 1; diff --git a/Source/cmake.h b/Source/cmake.h index 9dc429d..a21c9ca 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -24,6 +24,10 @@ #include <string> #include <vector> +#if defined(CMAKE_BUILD_WITH_CMAKE) +#include "cm_jsoncpp_value.h" +#endif + class cmExternalMakefileProjectGeneratorFactory; class cmFileTimeComparison; class cmGlobalGenerator; @@ -118,7 +122,10 @@ public: /// Destructor ~cmake(); - std::string ReportCapabilities() const; +#if defined(CMAKE_BUILD_WITH_CMAKE) + Json::Value ReportCapabilitiesJson(bool haveServerMode) const; +#endif + std::string ReportCapabilities(bool haveServerMode) const; static const char* GetCMakeFilesDirectory() { return "/CMakeFiles"; } static const char* GetCMakeFilesDirectoryPostSlash() @@ -186,6 +193,9 @@ public: return this->GlobalGenerator; } + ///! Return the full path to where the CMakeCache.txt file should be. + static std::string FindCacheFile(const std::string& binaryDir); + ///! Return the global generator assigned to this instance of cmake void SetGlobalGenerator(cmGlobalGenerator*); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index c2e1d53..38f00e6 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -23,6 +23,10 @@ #include "cm_auto_ptr.hxx" #include "cmake.h" +#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE +#include "cmServer.h" +#endif + #if defined(CMAKE_BUILD_WITH_CMAKE) #include "cmDependsFortran.h" // For -E cmake_copy_f90_mod callback. #endif @@ -91,9 +95,10 @@ void CMakeCommandUsage(const char* program) << " remove_directory dir - remove a directory and its contents\n" << " rename oldname newname - rename a file or directory " "(on one volume)\n" + << " server - start cmake in server mode\n" + << " sleep <number>... - sleep for given number of seconds\n" << " tar [cxt][vf][zjJ] file.tar [file/dir1 file/dir2 ...]\n" << " - create or extract a tar or zip archive\n" - << " sleep <number>... - sleep for given number of seconds\n" << " time command [args...] - run command and return elapsed time\n" << " touch file - touch a file.\n" << " touch_nocreate file - touch a file but do not create it.\n" @@ -527,7 +532,11 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) return 1; } cmake cm; - std::cout << cm.ReportCapabilities(); +#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE + std::cout << cm.ReportCapabilities(true); +#else + std::cout << cm.ReportCapabilities(false); +#endif return 0; } @@ -903,6 +912,36 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string>& args) #endif } return 0; + } else if (args[1] == "server") { + if (args.size() > 3) { + cmSystemTools::Error("Too many arguments to start server mode"); + return 1; + } + bool supportExperimental = false; + if (args.size() == 3) { + if (args[2] == "--experimental") { + supportExperimental = true; + } else { + cmSystemTools::Error("Unknown argument for server mode"); + return 1; + } + } +#if defined(HAVE_SERVER_MODE) && HAVE_SERVER_MODE + cmServer server(supportExperimental); + if (server.Serve()) { + return 0; + } else { + cmSystemTools::Error( + "CMake server could not find any supported protocol. " + "Try with \"--experimental\" to enable " + "experimental support."); + return 1; + } +#else + static_cast<void>(supportExperimental); + cmSystemTools::Error("CMake was not built with server mode enabled"); + return 1; +#endif } #if defined(CMAKE_BUILD_WITH_CMAKE) diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt index 87f6048..c4fe5e8 100644 --- a/Source/kwsys/CMakeLists.txt +++ b/Source/kwsys/CMakeLists.txt @@ -123,6 +123,7 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) SET(KWSYS_USE_FStream 1) SET(KWSYS_USE_String 1) SET(KWSYS_USE_SystemInformation 1) + SET(KWSYS_USE_ConsoleBuf 1) ENDIF() # Enforce component dependencies. @@ -154,6 +155,9 @@ ENDIF() IF(KWSYS_USE_FStream) SET(KWSYS_USE_Encoding 1) ENDIF() +IF(KWSYS_USE_ConsoleBuf) + SET(KWSYS_USE_Encoding 1) +ENDIF() # Setup the large file support default. IF(KWSYS_LFS_DISABLE) @@ -673,7 +677,7 @@ SET(KWSYS_HXX_FILES Configure String # Add selected C++ classes. SET(cppclasses Directory DynamicLoader Encoding Glob RegularExpression SystemTools - CommandLineArguments IOStream FStream SystemInformation + CommandLineArguments IOStream FStream SystemInformation ConsoleBuf ) FOREACH(cpp ${cppclasses}) IF(KWSYS_USE_${cpp}) @@ -926,6 +930,20 @@ IF(KWSYS_STANDALONE OR CMake_SOURCE_DIR) testFStream ) ENDIF() + IF(KWSYS_USE_ConsoleBuf) + ADD_EXECUTABLE(testConsoleBufChild testConsoleBufChild.cxx) + SET_PROPERTY(TARGET testConsoleBufChild PROPERTY LABELS ${KWSYS_LABELS_EXE}) + TARGET_LINK_LIBRARIES(testConsoleBufChild ${KWSYS_NAMESPACE}) + SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} + testConsoleBuf + ) + IF("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC" AND + NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0") + set_property(SOURCE testConsoleBuf.cxx testConsoleBufChild.cxx PROPERTY COMPILE_FLAGS /utf-8) + ENDIF() + SET_PROPERTY(SOURCE testConsoleBuf.cxx APPEND PROPERTY COMPILE_DEFINITIONS + KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE}) + ENDIF() IF(KWSYS_USE_SystemInformation) SET(KWSYS_CXX_TESTS ${KWSYS_CXX_TESTS} testSystemInformation) ENDIF() diff --git a/Source/kwsys/ConsoleBuf.hxx.in b/Source/kwsys/ConsoleBuf.hxx.in new file mode 100644 index 0000000..8aeeda1 --- /dev/null +++ b/Source/kwsys/ConsoleBuf.hxx.in @@ -0,0 +1,348 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef @KWSYS_NAMESPACE@_ConsoleBuf_hxx +#define @KWSYS_NAMESPACE@_ConsoleBuf_hxx + +#include <@KWSYS_NAMESPACE@/Configure.hxx> +#include <@KWSYS_NAMESPACE@/Encoding.hxx> +#include <string> +#include <cstring> +#include <sstream> +#include <streambuf> +#include <iostream> +#include <stdexcept> + +#if defined(_WIN32) +# include <windows.h> +# if __cplusplus >= 201103L +# include <system_error> +# endif +#endif + +namespace @KWSYS_NAMESPACE@ +{ +#if defined(_WIN32) + + template<class CharT, class Traits = std::char_traits<CharT> > + class @KWSYS_NAMESPACE@_EXPORT BasicConsoleBuf : + public std::basic_streambuf<CharT, Traits> { + public: + typedef typename Traits::int_type int_type; + typedef typename Traits::char_type char_type; + + class Manager { + public: + Manager(std::basic_ios<CharT, Traits> &ios, const bool err = false) + : m_consolebuf(0) + { + m_ios = &ios; + try { + m_consolebuf = new BasicConsoleBuf<CharT, Traits>(err); + m_streambuf = m_ios->rdbuf(m_consolebuf); + } catch (const std::runtime_error& ex) { + std::cerr << "Failed to create ConsoleBuf!" << std::endl + << ex.what() << std::endl; + }; + } + + ~Manager() + { + if (m_consolebuf) { + delete m_consolebuf; + m_ios->rdbuf(m_streambuf); + } + } + + private: + std::basic_ios<CharT, Traits> *m_ios; + std::basic_streambuf<CharT, Traits> *m_streambuf; + BasicConsoleBuf<CharT, Traits> *m_consolebuf; + }; + + BasicConsoleBuf(const bool err = false) : + flush_on_newline(true), + input_pipe_codepage(0), + output_pipe_codepage(0), + input_file_codepage(CP_UTF8), + output_file_codepage(CP_UTF8), + m_consolesCodepage(0) + { + m_hInput = ::GetStdHandle(STD_INPUT_HANDLE); + checkHandle(true, "STD_INPUT_HANDLE"); + if (!setActiveInputCodepage()) { + throw std::runtime_error("setActiveInputCodepage failed!"); + } + m_hOutput = err ? ::GetStdHandle(STD_ERROR_HANDLE) : + ::GetStdHandle(STD_OUTPUT_HANDLE); + checkHandle(false, err ? "STD_ERROR_HANDLE" : "STD_OUTPUT_HANDLE"); + if (!setActiveOutputCodepage()) { + throw std::runtime_error("setActiveOutputCodepage failed!"); + } + _setg(); + _setp(); + } + + ~BasicConsoleBuf() throw() + { + sync(); + } + + bool activateCodepageChange() + { + return setActiveInputCodepage() && setActiveOutputCodepage(); + } + + protected: + virtual int sync() { + bool success = true; + if (m_hInput && m_isConsoleInput && + ::FlushConsoleInputBuffer(m_hInput) == 0) { + success = false; + } + if (m_hOutput && !m_obuffer.empty()) { + const std::wstring wbuffer = getBuffer(m_obuffer); + if (m_isConsoleOutput) { + DWORD charsWritten; + success = ::WriteConsoleW(m_hOutput, wbuffer.c_str(), + (DWORD)wbuffer.size(), &charsWritten, + NULL) == 0 ? false : true; + } else { + DWORD bytesWritten; + std::string buffer; + success = encodeOutputBuffer(wbuffer, buffer); + if (success) { + success = ::WriteFile(m_hOutput, buffer.c_str(), + (DWORD)buffer.size(), &bytesWritten, + NULL) == 0 ? false : true; + } + } + } + m_ibuffer.clear(); + m_obuffer.clear(); + _setg(); + _setp(); + return success ? 0 : -1; + } + + virtual int_type underflow() { + if (this->gptr() >= this->egptr()) { + if (!m_hInput) { + _setg(true); + return Traits::eof(); + } + if (m_isConsoleInput) { + wchar_t wbuffer[128]; + DWORD charsRead; + if (::ReadConsoleW(m_hInput, wbuffer, (sizeof(wbuffer) / sizeof(wbuffer[0])) - 1, + &charsRead, NULL) == 0 || charsRead == 0) { + _setg(true); + return Traits::eof(); + } + wbuffer[charsRead] = L'\0'; + setBuffer(wbuffer, m_ibuffer); + } else { + std::wstring totalBuffer; + std::wstring wbuffer; + char buffer[128]; + DWORD bytesRead; + while (::ReadFile(m_hInput, buffer, (sizeof(buffer) / sizeof(buffer[0])) - 1, + &bytesRead, NULL) == 0) { + if (::GetLastError() == ERROR_MORE_DATA) { + buffer[bytesRead] = '\0'; + if (decodeInputBuffer(buffer, wbuffer)) { + totalBuffer += wbuffer; + continue; + } + } + _setg(true); + return Traits::eof(); + } + buffer[bytesRead] = '\0'; + if (!decodeInputBuffer(buffer, wbuffer)) { + _setg(true); + return Traits::eof(); + } + totalBuffer += wbuffer; + setBuffer(totalBuffer, m_ibuffer); + } + _setg(); + } + return Traits::to_int_type(*this->gptr()); + } + + virtual int_type overflow(int_type ch = Traits::eof()) { + if (!Traits::eq_int_type(ch, Traits::eof())) { + char_type chr = Traits::to_char_type(ch); + m_obuffer += chr; + if ((flush_on_newline && Traits::eq(chr, '\n')) || + Traits::eq_int_type(ch, 0x00)) { + sync(); + } + return ch; + } + sync(); + return Traits::eof(); + } + + public: + bool flush_on_newline; + UINT input_pipe_codepage; + UINT output_pipe_codepage; + UINT input_file_codepage; + UINT output_file_codepage; + + private: + HANDLE m_hInput; + HANDLE m_hOutput; + std::basic_string<char_type> m_ibuffer; + std::basic_string<char_type> m_obuffer; + bool m_isConsoleInput; + bool m_isConsoleOutput; + UINT m_activeInputCodepage; + UINT m_activeOutputCodepage; + UINT m_consolesCodepage; + void checkHandle(bool input, std::string handleName) { + if ((input && m_hInput == INVALID_HANDLE_VALUE) || + (!input && m_hOutput == INVALID_HANDLE_VALUE)) { + std::string errmsg = "GetStdHandle(" + handleName + + ") returned INVALID_HANDLE_VALUE"; +#if __cplusplus >= 201103L + throw std::system_error(::GetLastError(), + std::system_category(), errmsg); +#else + throw std::runtime_error(errmsg); +#endif + } + } + UINT getConsolesCodepage() { + if (!m_consolesCodepage) { + m_consolesCodepage = GetConsoleCP(); + if (!m_consolesCodepage) { + m_consolesCodepage = GetACP(); + } + } + return m_consolesCodepage; + } + bool setActiveInputCodepage() { + m_isConsoleInput = false; + switch (GetFileType(m_hInput)) { + case FILE_TYPE_DISK: + m_activeInputCodepage = input_file_codepage; + break; + case FILE_TYPE_CHAR: + m_isConsoleInput = true; + break; + case FILE_TYPE_PIPE: + m_activeInputCodepage = input_pipe_codepage; + break; + default: + return false; + } + if (!m_isConsoleInput && m_activeInputCodepage == 0) { + m_activeInputCodepage = getConsolesCodepage(); + } + return true; + } + bool setActiveOutputCodepage() { + m_isConsoleOutput = false; + switch (GetFileType(m_hOutput)) { + case FILE_TYPE_DISK: + m_activeOutputCodepage = output_file_codepage; + break; + case FILE_TYPE_CHAR: + m_isConsoleOutput = true; + break; + case FILE_TYPE_PIPE: + m_activeOutputCodepage = output_pipe_codepage; + break; + default: + return false; + } + if (!m_isConsoleOutput && m_activeOutputCodepage == 0) { + m_activeOutputCodepage = getConsolesCodepage(); + } + return true; + } + void _setg(bool empty = false) { + if (!empty) { + this->setg((char_type *)m_ibuffer.data(), + (char_type *)m_ibuffer.data(), + (char_type *)m_ibuffer.data() + m_ibuffer.size()); + } else { + this->setg((char_type *)m_ibuffer.data(), + (char_type *)m_ibuffer.data() + m_ibuffer.size(), + (char_type *)m_ibuffer.data() + m_ibuffer.size()); + } + } + void _setp() { + this->setp((char_type *)m_obuffer.data(), + (char_type *)m_obuffer.data() + m_obuffer.size()); + } + bool encodeOutputBuffer(const std::wstring wbuffer, + std::string &buffer) { + const int length = WideCharToMultiByte(m_activeOutputCodepage, 0, + wbuffer.c_str(), + (int)wbuffer.size(), NULL, 0, + NULL, NULL); + char *buf = new char[length + 1]; + const bool success = WideCharToMultiByte(m_activeOutputCodepage, 0, + wbuffer.c_str(), + (int)wbuffer.size(), buf, + length, NULL, NULL) > 0 + ? true : false; + buf[length] = '\0'; + buffer = buf; + delete[] buf; + return success; + } + bool decodeInputBuffer(const char *buffer, std::wstring &wbuffer) { + int actualCodepage = m_activeInputCodepage; + const char BOM_UTF8[] = { char(0xEF), char(0xBB), char(0xBF) }; + if (std::memcmp(buffer, BOM_UTF8, sizeof(BOM_UTF8)) == 0) { + // PowerShell uses UTF-8 with BOM for pipes + actualCodepage = CP_UTF8; + buffer += sizeof(BOM_UTF8); + } + const int wlength = MultiByteToWideChar(actualCodepage, 0, buffer, + -1, NULL, 0); + wchar_t *wbuf = new wchar_t[wlength]; + const bool success = MultiByteToWideChar(actualCodepage, 0, buffer, + -1, wbuf, wlength) > 0 + ? true : false; + wbuffer = wbuf; + delete[] wbuf; + return success; + } + std::wstring getBuffer(const std::basic_string<char> buffer) { + return Encoding::ToWide(buffer); + } + std::wstring getBuffer(const std::basic_string<wchar_t> buffer) { + return buffer; + } + void setBuffer(const std::wstring wbuffer, + std::basic_string<char> &target) { + target = Encoding::ToNarrow(wbuffer); + } + void setBuffer(const std::wstring wbuffer, + std::basic_string<wchar_t> &target) { + target = wbuffer; + } + + }; // BasicConsoleBuf class + + typedef BasicConsoleBuf<char> ConsoleBuf; + typedef BasicConsoleBuf<wchar_t> WConsoleBuf; + +#endif +} // KWSYS_NAMESPACE + +#endif diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 1a73b16..4281c38 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -3982,16 +3982,16 @@ std::string SystemTools::RelativePath(const std::string& local, const std::strin } #ifdef _WIN32 -static int GetCasePathName(const std::string & pathIn, - std::string & casePath) +static std::string GetCasePathName(std::string const& pathIn) { + std::string casePath; std::vector<std::string> path_components; SystemTools::SplitPath(pathIn, path_components); if(path_components[0].empty()) // First component always exists. { // Relative paths cannot be converted. - casePath = ""; - return 0; + casePath = pathIn; + return casePath; } // Start with root component. @@ -4015,38 +4015,45 @@ static int GetCasePathName(const std::string & pathIn, sep = "/"; } + // Convert case of all components that exist. + bool converting = true; for(; idx < path_components.size(); idx++) { casePath += sep; sep = "/"; - std::string test_str = casePath; - test_str += path_components[idx]; - - // If path component contains wildcards, we skip matching - // because these filenames are not allowed on windows, - // and we do not want to match a different file. - if(path_components[idx].find('*') != std::string::npos || - path_components[idx].find('?') != std::string::npos) - { - casePath = ""; - return 0; - } - WIN32_FIND_DATAW findData; - HANDLE hFind = ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), - &findData); - if (INVALID_HANDLE_VALUE != hFind) - { - casePath += Encoding::ToNarrow(findData.cFileName); - ::FindClose(hFind); - } - else + if (converting) { - casePath = ""; - return 0; + // If path component contains wildcards, we skip matching + // because these filenames are not allowed on windows, + // and we do not want to match a different file. + if(path_components[idx].find('*') != std::string::npos || + path_components[idx].find('?') != std::string::npos) + { + converting = false; + } + else + { + std::string test_str = casePath; + test_str += path_components[idx]; + WIN32_FIND_DATAW findData; + HANDLE hFind = ::FindFirstFileW(Encoding::ToWide(test_str).c_str(), + &findData); + if (INVALID_HANDLE_VALUE != hFind) + { + path_components[idx] = Encoding::ToNarrow(findData.cFileName); + ::FindClose(hFind); + } + else + { + converting = false; + } + } } + + casePath += path_components[idx]; } - return (int)casePath.size(); + return casePath; } #endif @@ -4065,11 +4072,10 @@ std::string SystemTools::GetActualCaseForPath(const std::string& p) { return i->second; } - std::string casePath; - int len = GetCasePathName(p, casePath); - if(len == 0 || len > MAX_PATH+1) + std::string casePath = GetCasePathName(p); + if (casePath.size() > MAX_PATH) { - return p; + return casePath; } (*SystemTools::PathCaseMap)[p] = casePath; return casePath; diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 28ff0b3..5849145 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -374,10 +374,11 @@ public: static const char* GetExecutableExtension(); /** - * Given a path that exists on a windows machine, return the - * actuall case of the path as it was created. If the file - * does not exist path is returned unchanged. This does nothing - * on unix but return path. + * Given a path on a Windows machine, return the actual case of + * the path as it exists on disk. Path components that do not + * exist on disk are returned unchanged. Relative paths are always + * returned unchanged. Drive letters are always made upper case. + * This does nothing on non-Windows systems but return the path. */ static std::string GetActualCaseForPath(const std::string& path); diff --git a/Source/kwsys/testConsoleBuf.cxx b/Source/kwsys/testConsoleBuf.cxx new file mode 100644 index 0000000..3dc3337 --- /dev/null +++ b/Source/kwsys/testConsoleBuf.cxx @@ -0,0 +1,714 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "kwsysPrivate.h" + +// Ignore Windows version levels defined by command-line flags. This +// source needs access to all APIs available on the host in order for +// the test to run properly. The test binary is not installed anyway. +#undef _WIN32_WINNT +#undef NTDDI_VERSION + +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "Encoding.hxx.in" +#endif + +#if defined(_WIN32) + +#include <windows.h> +#include <string.h> +#include <wchar.h> +#include <iostream> +#include <iomanip> +#include <stdexcept> +#include "testConsoleBuf.hxx" + +#if defined(_MSC_VER) && _MSC_VER >= 1800 +# define KWSYS_WINDOWS_DEPRECATED_GetVersion +#endif +// يونيكود +static const WCHAR UnicodeInputTestString[] = L"\u064A\u0648\u0646\u064A\u0643\u0648\u062F!"; +static UINT TestCodepage = KWSYS_ENCODING_DEFAULT_CODEPAGE; + +static const DWORD waitTimeout = 10 * 1000; +static STARTUPINFO startupInfo; +static PROCESS_INFORMATION processInfo; +static HANDLE beforeInputEvent; +static HANDLE afterOutputEvent; +static std::string encodedInputTestString; +static std::string encodedTestString; + +static void displayError(DWORD errorCode) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "Failed with error: 0x" << errorCode << "!" << std::endl; + LPWSTR message; + if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errorCode, + 0, + (LPWSTR)&message, 0, + NULL) + ) { + std::cerr << "Error message: " << kwsys::Encoding::ToNarrow(message) << std::endl; + HeapFree(GetProcessHeap(), 0, message); + } else { + std::cerr << "FormatMessage() failed with error: 0x" << GetLastError() << "!" << std::endl; + } + std::cerr.unsetf(std::ios::hex); +} + +std::basic_streambuf<char> *errstream(const char *unused) { + static_cast<void>(unused); + return std::cerr.rdbuf(); +} + +std::basic_streambuf<wchar_t> *errstream(const wchar_t *unused) { + static_cast<void>(unused); + return std::wcerr.rdbuf(); +} + +//---------------------------------------------------------------------------- +template<typename T> +static void dumpBuffers(const T *expected, const T *received, size_t size) { + std::basic_ostream<T> err(errstream(expected)); + err << "Expected output: '" << std::basic_string<T>(expected, size) << "'" << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + err << "Received output: '" << std::basic_string<T>(received, size) << "'" << std::endl; + if (err.fail()) { + err.clear(); + err << "--- Error while outputting ---" << std::endl; + } + std::cerr << "Expected output | Received output" << std::endl; + for (size_t i = 0; i < size; i++) { + std::cerr << std::setbase(16) << std::setfill('0') << " " << + "0x" << std::setw(8) << static_cast<unsigned int>(expected[i]) << " | " << + "0x" << std::setw(8) << static_cast<unsigned int>(received[i]); + if (static_cast<unsigned int>(expected[i]) != static_cast<unsigned int>(received[i])) { + std::cerr << " MISMATCH!"; + } + std::cerr << std::endl; + } + std::cerr << std::endl << std::flush; +} + +//---------------------------------------------------------------------------- +static bool createProcess(HANDLE hIn, HANDLE hOut, HANDLE hErr) +{ + BOOL bInheritHandles = FALSE; + DWORD dwCreationFlags = 0; + memset(&processInfo, 0, sizeof(processInfo)); + memset(&startupInfo, 0, sizeof(startupInfo)); + startupInfo.cb = sizeof(startupInfo); + startupInfo.dwFlags = STARTF_USESHOWWINDOW; + startupInfo.wShowWindow = SW_HIDE; + if (hIn || hOut || hErr) { + startupInfo.dwFlags |= STARTF_USESTDHANDLES; + startupInfo.hStdInput = hIn; + startupInfo.hStdOutput = hOut; + startupInfo.hStdError = hErr; + bInheritHandles = TRUE; + } + + WCHAR cmd[MAX_PATH]; + if (GetModuleFileNameW(NULL, cmd, MAX_PATH) == 0) { + std::cerr << "GetModuleFileName failed!" << std::endl; + return false; + } + WCHAR *p = cmd + wcslen(cmd); + while (p > cmd && *p != L'\\') p--; + *(p+1) = 0; + wcscat(cmd, cmdConsoleBufChild); + wcscat(cmd, L".exe"); + + bool success = CreateProcessW(NULL, // No module name (use command line) + cmd, // Command line + NULL, // Process handle not inheritable + NULL, // Thread handle not inheritable + bInheritHandles, // Set handle inheritance + dwCreationFlags, + NULL, // Use parent's environment block + NULL, // Use parent's starting directory + &startupInfo, // Pointer to STARTUPINFO structure + &processInfo) != 0; // Pointer to PROCESS_INFORMATION structure + if (!success) { + DWORD lastError = GetLastError(); + std::cerr << "CreateProcess(" << kwsys::Encoding::ToNarrow(cmd) << ")" << std::endl; + displayError(lastError); + } + return success; +} + +//---------------------------------------------------------------------------- +static void finishProcess(bool success) +{ + if (success) { + success = WaitForSingleObject(processInfo.hProcess, waitTimeout) + == WAIT_OBJECT_0; + }; + if (!success) { + TerminateProcess(processInfo.hProcess, 1); + } + CloseHandle(processInfo.hProcess); + CloseHandle(processInfo.hThread); +} + +//---------------------------------------------------------------------------- +static bool createPipe(PHANDLE readPipe, PHANDLE writePipe) +{ + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = NULL; + return CreatePipe(readPipe, writePipe, &securityAttributes, 0) == 0 + ? false : true; +} + +//---------------------------------------------------------------------------- +static void finishPipe(HANDLE readPipe, HANDLE writePipe) +{ + if (readPipe != INVALID_HANDLE_VALUE) { + CloseHandle(readPipe); + } + if (writePipe != INVALID_HANDLE_VALUE) { + CloseHandle(writePipe); + } +} + +//---------------------------------------------------------------------------- +static HANDLE createFile(LPCWSTR fileName) +{ + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = NULL; + + HANDLE file = CreateFileW(fileName, + GENERIC_READ | GENERIC_WRITE, + 0, // do not share + &securityAttributes, + CREATE_ALWAYS, // overwrite existing + FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, + NULL); // no template + if (file == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(" << kwsys::Encoding::ToNarrow(fileName) << ")" << std::endl; + displayError(lastError); + } + return file; +} + +//---------------------------------------------------------------------------- +static void finishFile(HANDLE file) +{ + if (file != INVALID_HANDLE_VALUE) { + CloseHandle(file); + } +} + +//---------------------------------------------------------------------------- + +#ifndef MAPVK_VK_TO_VSC +# define MAPVK_VK_TO_VSC (0) +#endif + +static void writeInputKeyEvent(INPUT_RECORD inputBuffer[], WCHAR chr) +{ + inputBuffer[0].EventType = KEY_EVENT; + inputBuffer[0].Event.KeyEvent.bKeyDown = TRUE; + inputBuffer[0].Event.KeyEvent.wRepeatCount = 1; + SHORT keyCode = VkKeyScanW(chr); + if (keyCode == -1) { + // Character can't be entered with current keyboard layout + // Just set any, it doesn't really matter + keyCode = 'K'; + } + inputBuffer[0].Event.KeyEvent.wVirtualKeyCode = LOBYTE(keyCode); + inputBuffer[0].Event.KeyEvent.wVirtualScanCode = + MapVirtualKey(inputBuffer[0].Event.KeyEvent.wVirtualKeyCode, + MAPVK_VK_TO_VSC); + inputBuffer[0].Event.KeyEvent.uChar.UnicodeChar = chr; + inputBuffer[0].Event.KeyEvent.dwControlKeyState = 0; + if ((HIBYTE(keyCode) & 1) == 1) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED; + } + if ((HIBYTE(keyCode) & 2) == 2) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_CTRL_PRESSED; + } + if ((HIBYTE(keyCode) & 4) == 4) { + inputBuffer[0].Event.KeyEvent.dwControlKeyState |= RIGHT_ALT_PRESSED; + } + inputBuffer[1].EventType = inputBuffer[0].EventType; + inputBuffer[1].Event.KeyEvent.bKeyDown = FALSE; + inputBuffer[1].Event.KeyEvent.wRepeatCount = 1; + inputBuffer[1].Event.KeyEvent.wVirtualKeyCode = inputBuffer[0].Event. + KeyEvent.wVirtualKeyCode; + inputBuffer[1].Event.KeyEvent.wVirtualScanCode = inputBuffer[0].Event. + KeyEvent.wVirtualScanCode; + inputBuffer[1].Event.KeyEvent.uChar.UnicodeChar = inputBuffer[0].Event. + KeyEvent.uChar.UnicodeChar; + inputBuffer[1].Event.KeyEvent.dwControlKeyState = 0; +} + +//---------------------------------------------------------------------------- +static int testPipe() +{ + int didFail = 1; + HANDLE inPipeRead = INVALID_HANDLE_VALUE; + HANDLE inPipeWrite = INVALID_HANDLE_VALUE; + HANDLE outPipeRead = INVALID_HANDLE_VALUE; + HANDLE outPipeWrite = INVALID_HANDLE_VALUE; + HANDLE errPipeRead = INVALID_HANDLE_VALUE; + HANDLE errPipeWrite = INVALID_HANDLE_VALUE; + UINT currentCodepage = GetConsoleCP(); + char buffer[200]; + char buffer2[200]; + try { + if (!createPipe(&inPipeRead, &inPipeWrite) || + !createPipe(&outPipeRead, &outPipeWrite) || + !createPipe(&errPipeRead, &errPipeWrite)) { + throw std::runtime_error("createFile failed!"); + } + if (TestCodepage == CP_ACP) { + TestCodepage = GetACP(); + } + if (!SetConsoleCP(TestCodepage)) { + throw std::runtime_error("SetConsoleCP failed!"); + } + + DWORD bytesWritten = 0; + if (!WriteFile(inPipeWrite, encodedInputTestString.c_str(), + (DWORD)encodedInputTestString.size(), &bytesWritten, NULL) + || bytesWritten == 0) { + throw std::runtime_error("WriteFile failed!"); + } + + if (createProcess(inPipeRead, outPipeWrite, errPipeWrite)) { + try { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject failed!"); + } + DWORD bytesRead = 0; + if (!ReadFile(outPipeRead, buffer, sizeof(buffer), &bytesRead, NULL) + || bytesRead == 0) { + throw std::runtime_error("ReadFile#1 failed!"); + } + if ((bytesRead < encodedTestString.size() + 1 + encodedInputTestString.size() + && !ReadFile(outPipeRead, buffer + bytesRead, + sizeof(buffer) - bytesRead, &bytesRead, NULL)) + || bytesRead == 0) { + throw std::runtime_error("ReadFile#2 failed!"); + } + if (memcmp(buffer, encodedTestString.c_str(), + encodedTestString.size()) == 0 && + memcmp(buffer + encodedTestString.size() + 1, + encodedInputTestString.c_str(), + encodedInputTestString.size()) == 0) { + bytesRead = 0; + if (!ReadFile(errPipeRead, buffer2, sizeof(buffer2), &bytesRead, NULL) + || bytesRead == 0) { + throw std::runtime_error("ReadFile#3 failed!"); + } + buffer2[bytesRead - 1] = 0; + didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; + } + if (didFail != 0) { + std::cerr << "Pipe's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size()); + dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size()); + dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size()); + } + } catch (const std::runtime_error &ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); + } + finishProcess(didFail == 0); + } + } catch (const std::runtime_error &ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); + } + finishPipe(inPipeRead, inPipeWrite); + finishPipe(outPipeRead, outPipeWrite); + finishPipe(errPipeRead, errPipeWrite); + SetConsoleCP(currentCodepage); + return didFail; +} + +//---------------------------------------------------------------------------- +static int testFile() +{ + int didFail = 1; + HANDLE inFile = INVALID_HANDLE_VALUE; + HANDLE outFile = INVALID_HANDLE_VALUE; + HANDLE errFile = INVALID_HANDLE_VALUE; + try { + if ((inFile = createFile(L"stdinFile.txt")) == INVALID_HANDLE_VALUE || + (outFile = createFile(L"stdoutFile.txt")) == INVALID_HANDLE_VALUE || + (errFile = createFile(L"stderrFile.txt")) == INVALID_HANDLE_VALUE) { + throw std::runtime_error("createFile failed!"); + } + int length = 0; + DWORD bytesWritten = 0; + char buffer[200]; + char buffer2[200]; + + if ((length = WideCharToMultiByte(TestCodepage, 0, UnicodeInputTestString, -1, + buffer, sizeof(buffer), + NULL, NULL)) == 0) { + throw std::runtime_error("WideCharToMultiByte failed!"); + } + buffer[length - 1] = '\n'; + if (!WriteFile(inFile, buffer, length, &bytesWritten, NULL) + || bytesWritten == 0) { + throw std::runtime_error("WriteFile failed!"); + } + if (SetFilePointer(inFile, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer failed!"); + } + + if (createProcess(inFile, outFile, errFile)) { + DWORD bytesRead = 0; + try { + DWORD status; + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject failed!"); + } + if (SetFilePointer(outFile, 0, 0, FILE_BEGIN) + == INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer#1 failed!"); + } + if (!ReadFile(outFile, buffer, sizeof(buffer), &bytesRead, NULL) + || bytesRead == 0) { + throw std::runtime_error("ReadFile#1 failed!"); + } + buffer[bytesRead - 1] = 0; + if (memcmp(buffer, encodedTestString.c_str(), + encodedTestString.size()) == 0 && + memcmp(buffer + encodedTestString.size() + 1, + encodedInputTestString.c_str(), + encodedInputTestString.size() - 1) == 0) { + bytesRead = 0; + if (SetFilePointer(errFile, 0, 0, FILE_BEGIN) + == INVALID_SET_FILE_POINTER) { + throw std::runtime_error("SetFilePointer#2 failed!"); + } + if (!ReadFile(errFile, buffer2, sizeof(buffer2), &bytesRead, NULL) + || bytesRead == 0) { + throw std::runtime_error("ReadFile#2 failed!"); + } + buffer2[bytesRead - 1] = 0; + didFail = encodedTestString.compare(buffer2) == 0 ? 0 : 1; + } + if (didFail != 0) { + std::cerr << "File's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<char>(encodedTestString.c_str(), buffer, encodedTestString.size()); + dumpBuffers<char>(encodedInputTestString.c_str(), buffer + encodedTestString.size() + 1, encodedInputTestString.size() - 1); + dumpBuffers<char>(encodedTestString.c_str(), buffer2, encodedTestString.size()); + } + } catch (const std::runtime_error &ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); + } + finishProcess(didFail == 0); + } + } catch (const std::runtime_error &ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); + } + finishFile(inFile); + finishFile(outFile); + finishFile(errFile); + return didFail; +} + +#ifndef _WIN32_WINNT_VISTA +# define _WIN32_WINNT_VISTA 0x0600 +#endif + +//---------------------------------------------------------------------------- +static int testConsole() +{ + int didFail = 1; + HANDLE parentIn = GetStdHandle(STD_INPUT_HANDLE); + HANDLE parentOut = GetStdHandle(STD_OUTPUT_HANDLE); + HANDLE parentErr = GetStdHandle(STD_ERROR_HANDLE); + HANDLE hIn = parentIn; + HANDLE hOut = parentOut; + DWORD consoleMode; + bool newConsole = false; + bool forceNewConsole = false; + bool restoreConsole = false; + LPCWSTR TestFaceName = L"Lucida Console"; + const DWORD TestFontFamily = 0x00000036; + const DWORD TestFontSize = 0x000c0000; + HKEY hConsoleKey; + WCHAR FaceName[200]; + FaceName[0] = 0; + DWORD FaceNameSize = sizeof(FaceName); + DWORD FontFamily = TestFontFamily; + DWORD FontSize = TestFontSize; +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion +# pragma warning (push) +# ifdef __INTEL_COMPILER +# pragma warning (disable:1478) +# else +# pragma warning (disable:4996) +# endif +#endif + const bool isVistaOrGreater = LOBYTE(LOWORD(GetVersion())) >= HIBYTE(_WIN32_WINNT_VISTA); +#ifdef KWSYS_WINDOWS_DEPRECATED_GetVersion +# pragma warning (pop) +#endif + if (!isVistaOrGreater) { + if (RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, KEY_READ | KEY_WRITE, + &hConsoleKey) == ERROR_SUCCESS) { + DWORD dwordSize = sizeof(DWORD); + if (RegQueryValueExW(hConsoleKey, L"FontFamily", NULL, NULL, + (LPBYTE)&FontFamily, &dwordSize) == ERROR_SUCCESS) { + if (FontFamily != TestFontFamily) { + RegQueryValueExW(hConsoleKey, L"FaceName", NULL, NULL, + (LPBYTE)FaceName, &FaceNameSize); + RegQueryValueExW(hConsoleKey, L"FontSize", NULL, NULL, + (LPBYTE)&FontSize, &dwordSize); + + RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, + (BYTE *)&TestFontFamily, sizeof(TestFontFamily)); + RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, + (BYTE *)TestFaceName, (DWORD)((wcslen(TestFaceName) + 1) * sizeof(WCHAR))); + RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, + (BYTE *)&TestFontSize, sizeof(TestFontSize)); + + restoreConsole = true; + forceNewConsole = true; + } + } else { + std::cerr << "RegGetValueW(FontFamily) failed!" << std::endl << std::flush; + } + RegCloseKey(hConsoleKey); + } else { + std::cerr << "RegOpenKeyExW(HKEY_CURRENT_USER\\Console) failed!" << std::endl << std::flush; + } + } + if (forceNewConsole || GetConsoleMode(parentOut, &consoleMode) == 0) { + // Not a real console, let's create new one. + FreeConsole(); + if (!AllocConsole()) { + std::cerr << "AllocConsole failed!" << std::endl << std::flush; + return didFail; + } + SECURITY_ATTRIBUTES securityAttributes; + securityAttributes.nLength = sizeof(SECURITY_ATTRIBUTES); + securityAttributes.bInheritHandle = TRUE; + securityAttributes.lpSecurityDescriptor = NULL; + hIn = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + &securityAttributes, OPEN_EXISTING, 0, NULL); + if (hIn == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONIN$)" << std::endl; + displayError(lastError); + } + hOut = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, + &securityAttributes, OPEN_EXISTING, 0, NULL); + if (hOut == INVALID_HANDLE_VALUE) { + DWORD lastError = GetLastError(); + std::cerr << "CreateFile(CONOUT$)" << std::endl; + displayError(lastError); + } + SetStdHandle(STD_INPUT_HANDLE, hIn); + SetStdHandle(STD_OUTPUT_HANDLE, hOut); + SetStdHandle(STD_ERROR_HANDLE, hOut); + newConsole = true; + } + +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA + if (isVistaOrGreater) { + CONSOLE_FONT_INFOEX consoleFont; + memset(&consoleFont, 0, sizeof(consoleFont)); + consoleFont.cbSize = sizeof(consoleFont); + HMODULE kernel32 = LoadLibraryW(L"kernel32.dll"); + typedef BOOL (WINAPI *GetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); + typedef BOOL (WINAPI *SetCurrentConsoleFontExFunc)(HANDLE hConsoleOutput, BOOL bMaximumWindow, PCONSOLE_FONT_INFOEX lpConsoleCurrentFontEx); + GetCurrentConsoleFontExFunc getConsoleFont = (GetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "GetCurrentConsoleFontEx"); + SetCurrentConsoleFontExFunc setConsoleFont = (SetCurrentConsoleFontExFunc)GetProcAddress(kernel32, "SetCurrentConsoleFontEx"); + if (getConsoleFont(hOut, FALSE, &consoleFont)) { + if (consoleFont.FontFamily != TestFontFamily) { + consoleFont.FontFamily = TestFontFamily; + wcscpy(consoleFont.FaceName, TestFaceName); + if (!setConsoleFont(hOut, FALSE, &consoleFont)) { + std::cerr << "SetCurrentConsoleFontEx failed!" << std::endl << std::flush; + } + } + } else { + std::cerr << "GetCurrentConsoleFontEx failed!" << std::endl << std::flush; + } + } else { +#endif + if (restoreConsole && RegOpenKeyExW(HKEY_CURRENT_USER, L"Console", 0, + KEY_WRITE, &hConsoleKey) == ERROR_SUCCESS) { + RegSetValueExW(hConsoleKey, L"FontFamily", 0, REG_DWORD, + (BYTE *)&FontFamily, sizeof(FontFamily)); + if (FaceName[0] != 0) { + RegSetValueExW(hConsoleKey, L"FaceName", 0, REG_SZ, + (BYTE *)FaceName, FaceNameSize); + } else { + RegDeleteValueW(hConsoleKey, L"FaceName"); + } + RegSetValueExW(hConsoleKey, L"FontSize", 0, REG_DWORD, + (BYTE *)&FontSize, sizeof(FontSize)); + RegCloseKey(hConsoleKey); + } +#if _WIN32_WINNT >= _WIN32_WINNT_VISTA + } +#endif + + if (createProcess(NULL, NULL, NULL)) { + try { + DWORD status; + if ((status = WaitForSingleObject(beforeInputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#1 failed!"); + } + INPUT_RECORD inputBuffer[(sizeof(UnicodeInputTestString) / + sizeof(UnicodeInputTestString[0])) * 2]; + memset(&inputBuffer, 0, sizeof(inputBuffer)); + unsigned int i = 0; + for (i = 0; i < (sizeof(UnicodeInputTestString) / + sizeof(UnicodeInputTestString[0]) - 1); i++) { + writeInputKeyEvent(&inputBuffer[i*2], UnicodeInputTestString[i]); + } + writeInputKeyEvent(&inputBuffer[i*2], VK_RETURN); + DWORD eventsWritten = 0; + // We need to wait a bit before writing to console so child process have started waiting for input on stdin. + Sleep(300); + if (!WriteConsoleInputW(hIn, inputBuffer, sizeof(inputBuffer) / + sizeof(inputBuffer[0]), + &eventsWritten) || eventsWritten == 0) { + throw std::runtime_error("WriteConsoleInput failed!"); + } + if ((status = WaitForSingleObject(afterOutputEvent, waitTimeout)) != WAIT_OBJECT_0) { + std::cerr.setf(std::ios::hex, std::ios::basefield); + std::cerr << "WaitForSingleObject returned unexpected status 0x" << status << std::endl; + std::cerr.unsetf(std::ios::hex); + throw std::runtime_error("WaitForSingleObject#2 failed!"); + } + CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo; + if (!GetConsoleScreenBufferInfo(hOut, &screenBufferInfo)) { + throw std::runtime_error("GetConsoleScreenBufferInfo failed!"); + } + + COORD coord; + DWORD charsRead = 0; + coord.X = 0; + coord.Y = screenBufferInfo.dwCursorPosition.Y - 4; + WCHAR *outputBuffer = new WCHAR[screenBufferInfo.dwSize.X * 4]; + if (!ReadConsoleOutputCharacterW(hOut, outputBuffer, + screenBufferInfo.dwSize.X * 4, coord, &charsRead) + || charsRead == 0) { + delete[] outputBuffer; + throw std::runtime_error("ReadConsoleOutputCharacter failed!"); + } + std::wstring wideTestString = kwsys::Encoding::ToWide(encodedTestString); + std::wstring wideInputTestString = kwsys::Encoding::ToWide(encodedInputTestString); + if (memcmp(outputBuffer, wideTestString.c_str(), + wideTestString.size() * sizeof(wchar_t)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 1, + wideTestString.c_str(), wideTestString.size() * sizeof(wchar_t)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 2, + UnicodeInputTestString, sizeof(UnicodeInputTestString) - + sizeof(WCHAR)) == 0 && + memcmp(outputBuffer + screenBufferInfo.dwSize.X * 3, + wideInputTestString.c_str(), + (wideInputTestString.size() - 1) * sizeof(wchar_t)) == 0 + ) { + didFail = 0; + } else { + std::cerr << "Console's output didn't match expected output!" << std::endl << std::flush; + dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer, wideTestString.size()); + dumpBuffers<wchar_t>(wideTestString.c_str(), outputBuffer + screenBufferInfo.dwSize.X * 1, wideTestString.size()); + dumpBuffers<wchar_t>(UnicodeInputTestString, outputBuffer + screenBufferInfo.dwSize.X * 2, (sizeof(UnicodeInputTestString) - 1) / sizeof(WCHAR)); + dumpBuffers<wchar_t>(wideInputTestString.c_str(), outputBuffer + screenBufferInfo.dwSize.X * 3, wideInputTestString.size() - 1); + } + delete[] outputBuffer; + } catch (const std::runtime_error &ex) { + DWORD lastError = GetLastError(); + std::cerr << "In function " << __FUNCTION__ << ":" << ex.what() << std::endl << std::flush; + displayError(lastError); + } + finishProcess(didFail == 0); + } + if (newConsole) { + SetStdHandle(STD_INPUT_HANDLE, parentIn); + SetStdHandle(STD_OUTPUT_HANDLE, parentOut); + SetStdHandle(STD_ERROR_HANDLE, parentErr); + CloseHandle(hIn); + CloseHandle(hOut); + FreeConsole(); + } + return didFail; +} + +#endif + +//---------------------------------------------------------------------------- +int testConsoleBuf(int, char*[]) +{ + int ret = 0; + +#if defined(_WIN32) + beforeInputEvent = CreateEventW(NULL, + FALSE, // auto-reset event + FALSE, // initial state is nonsignaled + BeforeInputEventName); // object name + if (!beforeInputEvent) { + std::cerr << "CreateEvent#1 failed " << GetLastError() << std::endl; + return 1; + } + + afterOutputEvent = CreateEventW(NULL, FALSE, FALSE, AfterOutputEventName); + if (!afterOutputEvent) { + std::cerr << "CreateEvent#2 failed " << GetLastError() << std::endl; + return 1; + } + + encodedTestString = kwsys::Encoding::ToNarrow(UnicodeTestString); + encodedInputTestString = kwsys::Encoding::ToNarrow(UnicodeInputTestString); + encodedInputTestString += "\n"; + + ret |= testPipe(); + ret |= testFile(); + ret |= testConsole(); + + CloseHandle(beforeInputEvent); + CloseHandle(afterOutputEvent); +#endif + + return ret; +} diff --git a/Source/kwsys/testConsoleBuf.hxx b/Source/kwsys/testConsoleBuf.hxx new file mode 100644 index 0000000..7c2f4c6 --- /dev/null +++ b/Source/kwsys/testConsoleBuf.hxx @@ -0,0 +1,25 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#ifndef testConsoleBuf_hxx +#define testConsoleBuf_hxx + +static const wchar_t cmdConsoleBufChild[] = L"testConsoleBufChild"; + +static const wchar_t BeforeInputEventName[] = L"BeforeInputEvent"; +static const wchar_t AfterOutputEventName[] = L"AfterOutputEvent"; + +// यूनिकोड είναι здорово! +static const wchar_t UnicodeTestString[] = L"\u092F\u0942\u0928\u093F\u0915\u094B\u0921 " + L"\u03B5\u03AF\u03BD\u03B1\u03B9 " + L"\u0437\u0434\u043E\u0440\u043E\u0432\u043E!"; + +#endif diff --git a/Source/kwsys/testConsoleBufChild.cxx b/Source/kwsys/testConsoleBufChild.cxx new file mode 100644 index 0000000..2da39f2 --- /dev/null +++ b/Source/kwsys/testConsoleBufChild.cxx @@ -0,0 +1,63 @@ +/*============================================================================ + KWSys - Kitware System Library + Copyright 2000-2016 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "kwsysPrivate.h" + +#include KWSYS_HEADER(ConsoleBuf.hxx) +#include KWSYS_HEADER(Encoding.hxx) + +// Work-around CMake dependency scanning limitation. This must +// duplicate the above list of headers. +#if 0 +# include "ConsoleBuf.hxx.in" +# include "Encoding.hxx.in" +#endif + +#include <iostream> +#include "testConsoleBuf.hxx" + +//---------------------------------------------------------------------------- +int main(int argc, const char* argv[]) +{ +#if defined(_WIN32) + kwsys::ConsoleBuf::Manager out(std::cout); + kwsys::ConsoleBuf::Manager err(std::cerr, true); + kwsys::ConsoleBuf::Manager in(std::cin); + + if (argc > 1) { + std::cout << argv[1] << std::endl; + std::cerr << argv[1] << std::endl; + } else { + std::string str = kwsys::Encoding::ToNarrow(UnicodeTestString); + std::cout << str << std::endl; + std::cerr << str << std::endl; + } + + std::string input; + HANDLE event = OpenEventW(EVENT_MODIFY_STATE, FALSE, BeforeInputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); + } + + std::cin >> input; + std::cout << input << std::endl; + event = OpenEventW(EVENT_MODIFY_STATE, FALSE, AfterOutputEventName); + if (event) { + SetEvent(event); + CloseHandle(event); + } +#else + static_cast<void>(argc); + static_cast<void>(argv); +#endif + return 0; +} diff --git a/Source/kwsys/testSystemTools.cxx b/Source/kwsys/testSystemTools.cxx index 9252ea6..880b46e 100644 --- a/Source/kwsys/testSystemTools.cxx +++ b/Source/kwsys/testSystemTools.cxx @@ -940,7 +940,7 @@ static bool CheckRelativePath( const std::string& expected) { std::string result = kwsys::SystemTools::RelativePath(local, remote); - if(expected != result) + if (!kwsys::SystemTools::ComparePath(expected, result)) { std::cerr << "RelativePath(" << local << ", " << remote << ") yielded " << result << " instead of " << expected << std::endl; @@ -965,7 +965,7 @@ static bool CheckCollapsePath( const std::string& expected) { std::string result = kwsys::SystemTools::CollapseFullPath(path); - if(expected != result) + if (!kwsys::SystemTools::ComparePath(expected, result)) { std::cerr << "CollapseFullPath(" << path << ") yielded " << result << " instead of " << expected << std::endl; diff --git a/Tests/CMakeLib/CMakeLists.txt b/Tests/CMakeLib/CMakeLists.txt index 7ef3c03..405917a 100644 --- a/Tests/CMakeLib/CMakeLists.txt +++ b/Tests/CMakeLib/CMakeLists.txt @@ -11,6 +11,7 @@ set(CMakeLib_TESTS testUTF8 testXMLParser testXMLSafe + testFindPackageCommand ) set(testRST_ARGS ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/Tests/CMakeLib/testFindPackageCommand.cxx b/Tests/CMakeLib/testFindPackageCommand.cxx new file mode 100644 index 0000000..1cddb0e --- /dev/null +++ b/Tests/CMakeLib/testFindPackageCommand.cxx @@ -0,0 +1,76 @@ +/*============================================================================ + CMake - Cross Platform Makefile Generator + Copyright 2000-2011 Kitware, Inc., Insight Software Consortium + + Distributed under the OSI-approved BSD License (the "License"); + see accompanying file Copyright.txt for details. + + This software is distributed WITHOUT ANY WARRANTY; without even the + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the License for more information. +============================================================================*/ +#include "cmFindPackageCommand.h" + +#include <iostream> +#include <string> + +#define cmPassed(m) std::cout << "Passed: " << (m) << "\n" +#define cmFailed(m) \ + std::cout << "FAILED: " << (m) << "\n"; \ + failed = 1 + +int testFindPackageCommand(int /*unused*/, char* /*unused*/ []) +{ + int failed = 0; + + // ---------------------------------------------------------------------- + // Test cmFindPackage::Sort + std::vector<std::string> testString; + testString.push_back("lib-0.0"); + testString.push_back("lib-1.2"); + testString.push_back("lib-2.0"); + testString.push_back("lib-19.0.1"); + testString.push_back("lib-20.01.1"); + testString.push_back("lib-20.2.2a"); + + cmFindPackageCommand::Sort(testString.begin(), testString.end(), + cmFindPackageCommand::Natural, + cmFindPackageCommand::Asc); + if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" && + testString[2] == "lib-2.0" && testString[3] == "lib-19.0.1" && + testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) { + cmFailed("cmSystemTools::Sort fail with Natural ASC"); + } + + cmFindPackageCommand::Sort(testString.begin(), testString.end(), + cmFindPackageCommand::Natural, + cmFindPackageCommand::Dec); + if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" && + testString[3] == "lib-2.0" && testString[2] == "lib-19.0.1" && + testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) { + cmFailed("cmSystemTools::Sort fail with Natural ASC"); + } + + cmFindPackageCommand::Sort(testString.begin(), testString.end(), + cmFindPackageCommand::Name_order, + cmFindPackageCommand::Dec); + if (!(testString[5] == "lib-0.0" && testString[4] == "lib-1.2" && + testString[3] == "lib-19.0.1" && testString[2] == "lib-2.0" && + testString[1] == "lib-20.01.1" && testString[0] == "lib-20.2.2a")) { + cmFailed("cmSystemTools::Sort fail with Name DEC"); + } + + cmFindPackageCommand::Sort(testString.begin(), testString.end(), + cmFindPackageCommand::Name_order, + cmFindPackageCommand::Asc); + if (!(testString[0] == "lib-0.0" && testString[1] == "lib-1.2" && + testString[2] == "lib-19.0.1" && testString[3] == "lib-2.0" && + testString[4] == "lib-20.01.1" && testString[5] == "lib-20.2.2a")) { + cmFailed("cmSystemTools::Sort fail with Natural ASC"); + } + + if (!failed) { + cmPassed("cmSystemTools::Sort working"); + } + return failed; +} diff --git a/Tests/CMakeLib/testSystemTools.cxx b/Tests/CMakeLib/testSystemTools.cxx index e834b93..5b5c8d2 100644 --- a/Tests/CMakeLib/testSystemTools.cxx +++ b/Tests/CMakeLib/testSystemTools.cxx @@ -19,6 +19,13 @@ std::cout << "FAILED: " << (m) << "\n"; \ failed = 1 +#define cmAssert(exp, m) \ + if ((exp)) { \ + cmPassed(m); \ + } else { \ + cmFailed(m); \ + } + int testSystemTools(int /*unused*/, char* /*unused*/ []) { int failed = 0; @@ -26,10 +33,67 @@ int testSystemTools(int /*unused*/, char* /*unused*/ []) // Test cmSystemTools::UpperCase std::string str = "abc"; std::string strupper = "ABC"; - if (cmSystemTools::UpperCase(str) == strupper) { - cmPassed("cmSystemTools::UpperCase is working"); - } else { - cmFailed("cmSystemTools::UpperCase is working"); + cmAssert(cmSystemTools::UpperCase(str) == strupper, + "cmSystemTools::UpperCase"); + + // ---------------------------------------------------------------------- + // Test cmSystemTools::strverscmp + cmAssert(cmSystemTools::strverscmp("", "") == 0, "strverscmp empty string"); + cmAssert(cmSystemTools::strverscmp("abc", "") > 0, + "strverscmp string vs empty string"); + cmAssert(cmSystemTools::strverscmp("abc", "abc") == 0, + "strverscmp same string"); + cmAssert(cmSystemTools::strverscmp("abd", "abc") > 0, + "strverscmp character string"); + cmAssert(cmSystemTools::strverscmp("abc", "abd") < 0, + "strverscmp symmetric"); + cmAssert(cmSystemTools::strverscmp("12345", "12344") > 0, + "strverscmp natural numbers"); + cmAssert(cmSystemTools::strverscmp("100", "99") > 0, + "strverscmp natural numbers different digits"); + cmAssert(cmSystemTools::strverscmp("12345", "00345") > 0, + "strverscmp natural against decimal (same length)"); + cmAssert(cmSystemTools::strverscmp("99999999999999", "99999999999991") > 0, + "strverscmp natural overflow"); + cmAssert(cmSystemTools::strverscmp("00000000000009", "00000000000001") > 0, + "strverscmp deciaml precision"); + cmAssert(cmSystemTools::strverscmp("a.b.c.0", "a.b.c.000") > 0, + "strverscmp multiple zeros"); + cmAssert(cmSystemTools::strverscmp("lib_1.2_10", "lib_1.2_2") > 0, + "strverscmp last number "); + cmAssert(cmSystemTools::strverscmp("12lib", "2lib") > 0, + "strverscmp first number "); + cmAssert(cmSystemTools::strverscmp("02lib", "002lib") > 0, + "strverscmp first number decimal "); + cmAssert(cmSystemTools::strverscmp("10", "9a") > 0, + "strverscmp letter filler "); + cmAssert(cmSystemTools::strverscmp("000", "0001") > 0, + "strverscmp zero and leading zeros "); + + // test sorting using standard strvercmp input + std::vector<std::string> testString; + testString.push_back("000"); + testString.push_back("00"); + testString.push_back("01"); + testString.push_back("010"); + testString.push_back("09"); + testString.push_back("0"); + testString.push_back("1"); + testString.push_back("9"); + testString.push_back("10"); + + // test global ordering of input strings + for (size_t i = 0; i < testString.size() - 1; i++) { + for (size_t j = i + 1; j < testString.size(); j++) { + if (cmSystemTools::strverscmp(testString[i], testString[j]) >= 0) { + cmFailed("cmSystemTools::strverscmp error in comparing strings " + + testString[i] + " " + testString[j]); + } + } + } + + if (!failed) { + cmPassed("cmSystemTools::strverscmp working"); } return failed; } diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 97770ed..8cf1faa 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -2722,6 +2722,15 @@ ${CMake_BINARY_DIR}/bin/cmake -DDIR=dev -P ${CMake_SOURCE_DIR}/Utilities/Release ADD_TEST_MACRO(CMakeCommands.target_compile_definitions target_compile_definitions) ADD_TEST_MACRO(CMakeCommands.target_compile_options target_compile_options) + if(CMake_HAVE_SERVER_MODE) + # The cmake server-mode test requires python for a simple client. + find_package(PythonInterp QUIET) + if(PYTHON_EXECUTABLE) + set(Server_BUILD_OPTIONS -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE}) + ADD_TEST_MACRO(Server Server) + endif() + endif() + configure_file( "${CMake_SOURCE_DIR}/Tests/CTestTestCrash/test.cmake.in" "${CMake_BINARY_DIR}/Tests/CTestTestCrash/test.cmake" diff --git a/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake b/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake new file mode 100644 index 0000000..1cd44ff --- /dev/null +++ b/Tests/CMakeTests/String-TIMESTAMP-MonthWeekNames.cmake @@ -0,0 +1,11 @@ +string(TIMESTAMP output "%a;%b") +message("~${output}~") + +list(LENGTH output output_length) + +set(expected_output_length 2) + +if(NOT output_length EQUAL ${expected_output_length}) + message(FATAL_ERROR "expected ${expected_output_length} entries in output " + "with all specifiers; found ${output_length}") +endif() diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in index aba35fe..a45b205 100644 --- a/Tests/CMakeTests/StringTest.cmake.in +++ b/Tests/CMakeTests/StringTest.cmake.in @@ -36,6 +36,8 @@ set(TIMESTAMP-IncompleteSpecifier-RESULT 0) set(TIMESTAMP-IncompleteSpecifier-STDERR "~foobar%~") set(TIMESTAMP-AllSpecifiers-RESULT 0) set(TIMESTAMP-AllSpecifiers-STDERR "~[0-9]+(;[0-9]+)*~") +set(TIMESTAMP-MonthWeekNames-RESULT 0) +set(TIMESTAMP-MonthWeekNames-STDERR "~[^%]+;[^%]+~") set(TIMESTAMP-UnixTime-RESULT 0) set(TIMESTAMP-UnixTime-STDERR "~[1-9][0-9]+~") @@ -60,6 +62,7 @@ check_cmake_test(String TIMESTAMP-UnknownSpecifier TIMESTAMP-IncompleteSpecifier TIMESTAMP-AllSpecifiers + TIMESTAMP-MonthWeekNames TIMESTAMP-UnixTime ) diff --git a/Tests/FindPackageTest/CMakeLists.txt b/Tests/FindPackageTest/CMakeLists.txt index 04bbbc6..1a6f204 100644 --- a/Tests/FindPackageTest/CMakeLists.txt +++ b/Tests/FindPackageTest/CMakeLists.txt @@ -633,3 +633,33 @@ endif() if(PACKAGE_VERSION_UNSUITABLE) message(SEND_ERROR "PACKAGE_VERSION_UNSUITABLE set, but must not be !") endif() + + +############################################################################ +##Test FIND_PACKAGE using sorting +set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}) +SET(CMAKE_FIND_PACKAGE_SORT_ORDER NAME) +SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC) + +set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE) +FIND_PACKAGE(SortLib CONFIG) +IF (NOT "${SortLib_VERSION}" STREQUAL "3.1.1") + message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Name Asc! ${SortLib_VERSION}") +endif() +unset(SortLib_VERSION) + + +set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE) +SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) +SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC) +FIND_PACKAGE(SortLib CONFIG) +IF (NOT "${SortLib_VERSION}" STREQUAL "3.10.1") + message(SEND_ERROR "FIND_PACKAGE_SORT_ORDER Natural! Dec ${SortLib_VERSION}") +endif() +set(SortLib_DIR "" CACHE FILEPATH "Wipe out find results for testing." FORCE) +unset(SortLib_VERSION) + + +unset(CMAKE_FIND_PACKAGE_SORT_ORDER) +unset(CMAKE_FIND_PACKAGE_SORT_DIRECTION) +set(CMAKE_PREFIX_PATH ) diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake new file mode 100644 index 0000000..c1f2088 --- /dev/null +++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfig.cmake @@ -0,0 +1,2 @@ +set(SORT_LIB_VERSION 3.1.1) +message("SortLib 3.1.1 config reached") diff --git a/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake new file mode 100644 index 0000000..fa927c7 --- /dev/null +++ b/Tests/FindPackageTest/SortLib-3.1.1/SortLibConfigVersion.cmake @@ -0,0 +1,9 @@ +set(PACKAGE_VERSION 3.1.1) +if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3) + if(PACKAGE_FIND_VERSION_MINOR EQUAL 1) + set(PACKAGE_VERSION_COMPATIBLE 1) + if(PACKAGE_FIND_VERSION_PATCH EQUAL 1) + set(PACKAGE_VERSION_EXACT 1) + endif() + endif() +endif() diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake new file mode 100644 index 0000000..3f3f659 --- /dev/null +++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfig.cmake @@ -0,0 +1,2 @@ +set(SORT_LIB_VERSION 3.10.1) +message("SortLib 3.10.1 config reached") diff --git a/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake new file mode 100644 index 0000000..6f44c2d --- /dev/null +++ b/Tests/FindPackageTest/SortLib-3.10.1/SortLibConfigVersion.cmake @@ -0,0 +1,9 @@ +set(PACKAGE_VERSION 3.10.1) +if(PACKAGE_FIND_VERSION_MAJOR EQUAL 3) + if(PACKAGE_FIND_VERSION_MINOR EQUAL 10) + set(PACKAGE_VERSION_COMPATIBLE 1) + if(PACKAGE_FIND_VERSION_PATCH EQUAL 1) + set(PACKAGE_VERSION_EXACT 1) + endif() + endif() +endif() diff --git a/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake b/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake new file mode 100644 index 0000000..691e326 --- /dev/null +++ b/Tests/RunCMake/AndroidMK/AndroidMK-check.cmake @@ -0,0 +1,30 @@ +# This file does a regex file compare on the generated +# Android.mk files from the AndroidMK test + +macro(compare_file_to_expected file expected_file) + file(READ "${file}" ANDROID_MK) + # clean up new lines + string(REGEX REPLACE "\r\n" "\n" ANDROID_MK "${ANDROID_MK}") + string(REGEX REPLACE "\n+$" "" ANDROID_MK "${ANDROID_MK}") + # read in the expected regex file + file(READ "${expected_file}" expected) + # clean up new lines + string(REGEX REPLACE "\r\n" "\n" expected "${expected}") + string(REGEX REPLACE "\n+$" "" expected "${expected}") + # compare the file to the expected regex and if there is not a match + # put an error message in RunCMake_TEST_FAILED + if(NOT "${ANDROID_MK}" MATCHES "${expected}") + set(RunCMake_TEST_FAILED + "${file} does not match ${expected_file}: + +Android.mk contents = [\n${ANDROID_MK}\n] +Expected = [\n${expected}\n]") + endif() +endmacro() + +compare_file_to_expected( +"${RunCMake_BINARY_DIR}/AndroidMK-build/Android.mk" +"${RunCMake_TEST_SOURCE_DIR}/expectedBuildAndroidMK.txt") +compare_file_to_expected( +"${RunCMake_BINARY_DIR}/AndroidMK-build/CMakeFiles/Export/share/ndk-modules/Android.mk" +"${RunCMake_TEST_SOURCE_DIR}/expectedInstallAndroidMK.txt") diff --git a/Tests/RunCMake/AndroidMK/AndroidMK.cmake b/Tests/RunCMake/AndroidMK/AndroidMK.cmake new file mode 100644 index 0000000..ed21e58 --- /dev/null +++ b/Tests/RunCMake/AndroidMK/AndroidMK.cmake @@ -0,0 +1,11 @@ +project(build) +set(CMAKE_BUILD_TYPE Debug) +add_library(foo foo.cxx) +add_library(car foo.cxx) +add_library(bar foo.cxx) +add_library(dog foo.cxx) +target_link_libraries(foo car bar dog debug -lm) +export(TARGETS bar dog car foo ANDROID_MK + ${build_BINARY_DIR}/Android.mk) +install(TARGETS bar dog car foo DESTINATION lib EXPORT myexp) +install(EXPORT_ANDROID_MK myexp DESTINATION share/ndk-modules) diff --git a/Tests/RunCMake/AndroidMK/CMakeLists.txt b/Tests/RunCMake/AndroidMK/CMakeLists.txt new file mode 100644 index 0000000..576787a --- /dev/null +++ b/Tests/RunCMake/AndroidMK/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.5) +project(${RunCMake_TEST} NONE) # or languages needed +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake b/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake new file mode 100644 index 0000000..786d45b --- /dev/null +++ b/Tests/RunCMake/AndroidMK/RunCMakeTest.cmake @@ -0,0 +1,2 @@ +include(RunCMake) +run_cmake(AndroidMK) diff --git a/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt new file mode 100644 index 0000000..def8fcb --- /dev/null +++ b/Tests/RunCMake/AndroidMK/expectedBuildAndroidMK.txt @@ -0,0 +1,23 @@ +LOCAL_PATH.*call my-dir.* +include.*CLEAR_VARS.* +LOCAL_MODULE.*bar +LOCAL_SRC_FILES.*bar.* +include.*PREBUILT_STATIC_LIBRARY.* +.* +include.*CLEAR_VARS.* +LOCAL_MODULE.*dog +LOCAL_SRC_FILES.*.*dog.* +include.*PREBUILT_STATIC_LIBRARY.* +.* +include.*CLEAR_VARS.* +LOCAL_MODULE.*car +LOCAL_SRC_FILES.*.*car.* +include.*PREBUILT_STATIC_LIBRARY.* +.* +include.*CLEAR_VARS.* +LOCAL_MODULE.*foo +LOCAL_SRC_FILES.*.*foo.* +LOCAL_CPP_FEATURES.*rtti exceptions +LOCAL_STATIC_LIBRARIES.*car bar dog +LOCAL_EXPORT_LDLIBS := -lm +include.*PREBUILT_STATIC_LIBRARY.* diff --git a/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt new file mode 100644 index 0000000..1bdb308 --- /dev/null +++ b/Tests/RunCMake/AndroidMK/expectedInstallAndroidMK.txt @@ -0,0 +1,25 @@ +LOCAL_PATH.*call my-dir.* +_IMPORT_PREFIX.*LOCAL_PATH./../.. + +include.*CLEAR_VARS.* +LOCAL_MODULE.*bar +LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*bar.* +include.*PREBUILT_STATIC_LIBRARY.* + +include.*CLEAR_VARS. +LOCAL_MODULE.*dog +LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*dog.* +include.*PREBUILT_STATIC_LIBRARY.* + +include.*CLEAR_VARS.* +LOCAL_MODULE.*car +LOCAL_SRC_FILES.*_IMPORT_PREFIX./lib.*car.* +include.*PREBUILT_STATIC_LIBRARY.* + +include.*CLEAR_VARS.* +LOCAL_MODULE.*foo +LOCAL_SRC_FILES.*_IMPORT_PREFIX\)/lib.*foo.* +LOCAL_CPP_FEATURES.*rtti exceptions +LOCAL_STATIC_LIBRARIES.*car bar dog +LOCAL_EXPORT_LDLIBS := -lm +include.*PREBUILT_STATIC_LIBRARY.* diff --git a/Tests/RunCMake/AndroidMK/foo.cxx b/Tests/RunCMake/AndroidMK/foo.cxx new file mode 100644 index 0000000..3695dc9 --- /dev/null +++ b/Tests/RunCMake/AndroidMK/foo.cxx @@ -0,0 +1,3 @@ +void foo() +{ +} diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index ce475e0..a1f35d7 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -332,6 +332,8 @@ add_RunCMake_test_group(CPack "DEB;RPM;TGZ") # for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used add_RunCMake_test(AutoExportDll) +add_RunCMake_test(AndroidMK) + if(CMake_TEST_ANDROID_NDK OR CMake_TEST_ANDROID_STANDALONE_TOOLCHAIN) if(NOT "${CMAKE_GENERATOR}" MATCHES "Make|Ninja") message(FATAL_ERROR "Android tests supported only by Makefile and Ninja generators") diff --git a/Tests/RunCMake/CPack/CMakeLists.txt b/Tests/RunCMake/CPack/CMakeLists.txt index 46f1367..e42e971 100644 --- a/Tests/RunCMake/CPack/CMakeLists.txt +++ b/Tests/RunCMake/CPack/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.1 FATAL_ERROR) project(${RunCMake_TEST} CXX) -include(${RunCMake_TEST}.cmake) +include(${RunCMake_TEST_FILE_PREFIX}.cmake) # include test generator specifics -if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${GENERATOR_TYPE}/${RunCMake_TEST}-specifics.cmake") - include("${GENERATOR_TYPE}/${RunCMake_TEST}-specifics.cmake") +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${GENERATOR_TYPE}/${RunCMake_TEST_FILE_PREFIX}-specifics.cmake") + include("${GENERATOR_TYPE}/${RunCMake_TEST_FILE_PREFIX}-specifics.cmake") endif() set(CPACK_GENERATOR "${GENERATOR_TYPE}") diff --git a/Tests/RunCMake/CPack/CPackTestHelpers.cmake b/Tests/RunCMake/CPack/CPackTestHelpers.cmake index 7bf42f9..7e6b4b1 100644 --- a/Tests/RunCMake/CPack/CPackTestHelpers.cmake +++ b/Tests/RunCMake/CPack/CPackTestHelpers.cmake @@ -1,9 +1,15 @@ cmake_policy(SET CMP0057 NEW) -function(run_cpack_test TEST_NAME types build) +function(run_cpack_test_common_ TEST_NAME types build SUBTEST_SUFFIX source) if(TEST_TYPE IN_LIST types) set(RunCMake_TEST_NO_CLEAN TRUE) set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/${TEST_NAME}-build") + set(full_test_name_ "${TEST_NAME}") + + if(SUBTEST_SUFFIX) + set(RunCMake_TEST_BINARY_DIR "${RunCMake_TEST_BINARY_DIR}-${SUBTEST_SUFFIX}-subtest") + set(full_test_name_ "${full_test_name_}-${SUBTEST_SUFFIX}-subtest") + endif() # TODO this should be executed only once per ctest run (not per generator) file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") @@ -24,27 +30,48 @@ function(run_cpack_test TEST_NAME types build) endif() # execute cmake - set(RunCMake_TEST_OPTIONS "-DGENERATOR_TYPE=${TEST_TYPE}") - run_cmake(${TEST_NAME}) + set(RunCMake_TEST_OPTIONS "-DGENERATOR_TYPE=${TEST_TYPE}" + "-DRunCMake_TEST_FILE_PREFIX=${TEST_NAME}" + "-DRunCMake_SUBTEST_SUFFIX=${SUBTEST_SUFFIX}") + run_cmake(${full_test_name_}) # execute optional build step if(build) - run_cmake_command(${TEST_NAME}-Build "${CMAKE_COMMAND}" --build "${RunCMake_TEST_BINARY_DIR}") + run_cmake_command(${full_test_name_}-Build "${CMAKE_COMMAND}" --build "${RunCMake_TEST_BINARY_DIR}") + endif() + + if(source) + set(pack_params_ -G ${TEST_TYPE} --config ./CPackSourceConfig.cmake) + FILE(APPEND ${RunCMake_TEST_BINARY_DIR}/CPackSourceConfig.cmake + "\nset(CPACK_RPM_SOURCE_PKG_BUILD_PARAMS \"-DRunCMake_TEST:STRING=${full_test_name_}\ -DRunCMake_TEST_FILE_PREFIX:STRING=${TEST_NAME}\")") + else() + unset(pack_params_) endif() # execute cpack execute_process( - COMMAND "${CMAKE_CPACK_COMMAND}" + COMMAND ${CMAKE_CPACK_COMMAND} ${pack_params_} WORKING_DIRECTORY "${RunCMake_TEST_BINARY_DIR}" + RESULT_VARIABLE "result_" OUTPUT_FILE "${RunCMake_TEST_BINARY_DIR}/test_output.txt" ERROR_FILE "${RunCMake_TEST_BINARY_DIR}/test_error.txt" ) + foreach(o out err) + if(SUBTEST_SUFFIX AND EXISTS ${RunCMake_SOURCE_DIR}/${TEST_TYPE}/${TEST_NAME}-${SUBTEST_SUFFIX}-std${o}.txt) + set(RunCMake-std${o}-file "${TEST_TYPE}/${TEST_NAME}-${SUBTEST_SUFFIX}-std${o}.txt") + elseif(EXISTS ${RunCMake_SOURCE_DIR}/${TEST_TYPE}/${TEST_NAME}-std${o}.txt) + set(RunCMake-std${o}-file "${TEST_TYPE}/${TEST_NAME}-std${o}.txt") + endif() + endforeach() + # verify result run_cmake_command( - ${TEST_TYPE}/${TEST_NAME} + ${TEST_TYPE}/${full_test_name_} "${CMAKE_COMMAND}" - -DRunCMake_TEST=${TEST_NAME} + -DRunCMake_TEST=${full_test_name_} + -DRunCMake_TEST_FILE_PREFIX=${TEST_NAME} + -DRunCMake_SUBTEST_SUFFIX=${SUBTEST_SUFFIX} -DGENERATOR_TYPE=${TEST_TYPE} "-Dsrc_dir=${RunCMake_SOURCE_DIR}" "-Dbin_dir=${RunCMake_TEST_BINARY_DIR}" @@ -53,3 +80,17 @@ function(run_cpack_test TEST_NAME types build) ) endif() endfunction() + +function(run_cpack_test TEST_NAME types build) + run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "" false) +endfunction() + +function(run_cpack_source_test TEST_NAME types build) + run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "" true) +endfunction() + +function(run_cpack_test_subtests TEST_NAME SUBTEST_SUFFIXES types build) + foreach(suffix_ IN LISTS SUBTEST_SUFFIXES) + run_cpack_test_common_("${TEST_NAME}" "${types}" "${build}" "${suffix_}" false) + endforeach() +endfunction() diff --git a/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake b/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake new file mode 100644 index 0000000..5ca288c --- /dev/null +++ b/Tests/RunCMake/CPack/PACKAGE_CHECKSUM.cmake @@ -0,0 +1,4 @@ +install(FILES CMakeLists.txt DESTINATION foo) + +set(CPACK_PACKAGE_NAME "package_checksum") +set(CPACK_PACKAGE_CHECKSUM ${RunCMake_SUBTEST_SUFFIX}) diff --git a/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-ExpectedFiles.cmake b/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-ExpectedFiles.cmake new file mode 100644 index 0000000..d6811eb --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-ExpectedFiles.cmake @@ -0,0 +1,5 @@ +set(whitespaces_ "[\t\n\r ]*") + +set(EXPECTED_FILES_COUNT "1") +set(EXPECTED_FILE_1 "source_package*.src.rpm") +set(EXPECTED_FILE_CONTENT_1 "^source_package-0.1.1.tar.gz${whitespaces_}source_package.spec$") diff --git a/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-VerifyResult.cmake b/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-VerifyResult.cmake new file mode 100644 index 0000000..a84e296 --- /dev/null +++ b/Tests/RunCMake/CPack/RPM/SOURCE_PACKAGE-VerifyResult.cmake @@ -0,0 +1,63 @@ +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILD") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/BUILDROOT") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SOURCES") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SPECS") +file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/SRPMS") + +# make sure that we are using the version of cmake and cpack that we are testing +get_filename_component(cpack_path_ "${CMAKE_CPACK_COMMAND}" DIRECTORY) +set(ENV{PATH} "${cpack_path_}:$ENV{PATH}") + +execute_process(COMMAND ${RPMBUILD_EXECUTABLE} --define "_topdir ${CMAKE_CURRENT_BINARY_DIR}/test_rpm" --rebuild ${FOUND_FILE_1} + RESULT_VARIABLE result_ + ERROR_VARIABLE error_ + OUTPUT_QUIET + ) + +set(output_error_message_ + "\n${RPMBUILD_EXECUTABLE} error: '${error_}';\nresult: '${result_}';\n${output_error_message}") + +set(EXPECTED_FILE_CONTENT_ "^/foo${whitespaces_}/foo/test_prog$") + +file(GLOB_RECURSE FOUND_FILE_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/*.rpm") +list(APPEND foundFiles_ "${FOUND_FILE_}") +list(LENGTH FOUND_FILE_ foundFilesCount_) + +if(foundFilesCount_ EQUAL 1) + unset(PACKAGE_CONTENT) + getPackageContent("${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS/${FOUND_FILE_}" "PACKAGE_CONTENT") + + string(REGEX MATCH "${EXPECTED_FILE_CONTENT_}" + expected_content_list "${PACKAGE_CONTENT}") + + if(NOT expected_content_list) + message(FATAL_ERROR + "Unexpected file content!\n" + " Content: '${PACKAGE_CONTENT}'\n\n" + " Expected: '${EXPECTED_FILE_CONTENT_}'" + "${output_error_message_}") + endif() +else() + message(FATAL_ERROR + "Found more than one file!" + " Found files count '${foundFilesCount_}'." + " Files: '${FOUND_FILE_}'" + "${output_error_message_}") +endif() + +# check that there were no extra files generated +foreach(all_files_glob_ IN LISTS ALL_FILES_GLOB) + file(GLOB foundAll_ RELATIVE "${CMAKE_CURRENT_BINARY_DIR}/test_rpm/RPMS" "${all_files_glob_}") + list(APPEND allFoundFiles_ "${foundAll_}") +endforeach() + +list(LENGTH foundFiles_ foundFilesCount_) +list(LENGTH allFoundFiles_ allFoundFilesCount_) + +if(NOT foundFilesCount_ EQUAL allFoundFilesCount_) + message(FATAL_ERROR + "Found more files than expected! Found files: '${allFoundFiles_}'" + "${output_error_message_}") +endif() diff --git a/Tests/RunCMake/CPack/RunCMakeTest.cmake b/Tests/RunCMake/CPack/RunCMakeTest.cmake index a3029cf..60d42ac 100644 --- a/Tests/RunCMake/CPack/RunCMakeTest.cmake +++ b/Tests/RunCMake/CPack/RunCMakeTest.cmake @@ -5,6 +5,7 @@ include("${RunCMake_SOURCE_DIR}/CPackTestHelpers.cmake") # args: TEST_NAME "GENERATORS" RUN_CMAKE_BUILD_STEP run_cpack_test(MINIMAL "RPM;DEB;TGZ" false) +run_cpack_source_test(SOURCE_PACKAGE "RPM" true) run_cpack_test(PARTIALLY_RELOCATABLE_WARNING "RPM" false) run_cpack_test(DEB_EXTRA "DEB" false) run_cpack_test(DEPENDENCIES "RPM;DEB" true) @@ -18,3 +19,4 @@ run_cpack_test(DEB_GENERATE_SHLIBS "DEB" true) run_cpack_test(DEB_GENERATE_SHLIBS_LDCONFIG "DEB" true) run_cpack_test(DEBUGINFO "RPM" true) run_cpack_test(LONG_FILENAMES "DEB" false) +run_cpack_test_subtests(PACKAGE_CHECKSUM "invalid;MD5;SHA1;SHA224;SHA256;SHA384;SHA512" "TGZ" false) diff --git a/Tests/RunCMake/CPack/SOURCE_PACKAGE.cmake b/Tests/RunCMake/CPack/SOURCE_PACKAGE.cmake new file mode 100644 index 0000000..9958c2a --- /dev/null +++ b/Tests/RunCMake/CPack/SOURCE_PACKAGE.cmake @@ -0,0 +1,9 @@ +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/main.cpp" + "int main() {return 0;}") +add_executable(test_prog "${CMAKE_CURRENT_BINARY_DIR}/main.cpp") + +install(TARGETS test_prog DESTINATION foo COMPONENT applications) + +set(CPACK_RPM_FILE_NAME "RPM-DEFAULT") + +set(CPACK_PACKAGE_NAME "source_package") diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake new file mode 100644 index 0000000..205dcd8 --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-ExpectedFiles.cmake @@ -0,0 +1,9 @@ +set(whitespaces_ "[\t\n\r ]*") + +set(EXPECTED_FILES_COUNT "0") + +if (NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid") + set(EXPECTED_FILES_COUNT "1") + set(EXPECTED_FILE_1 "package_checksum*.tar.gz") + set(EXPECTED_FILE_CONTENT_1 "^[^\n]*package_checksum*-[^\n]*/foo/\n[^\n]*package_checksum-[^\n]*/foo/CMakeLists.txt$") +endif() diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake new file mode 100644 index 0000000..e9e65d6 --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-VerifyResult.cmake @@ -0,0 +1,14 @@ +if(NOT ${RunCMake_SUBTEST_SUFFIX} MATCHES "invalid") + string(TOLOWER ${RunCMake_SUBTEST_SUFFIX} EXTENSION) + file(GLOB PACKAGE RELATIVE ${bin_dir} "*.tar.gz") + file(GLOB CSUMFILE RELATIVE ${bin_dir} "*.${EXTENSION}") + file(STRINGS ${CSUMFILE} CHSUM_VALUE) + file(${RunCMake_SUBTEST_SUFFIX} ${PACKAGE} expected_value ) + set(expected_value "${expected_value} ${PACKAGE}") + + if(NOT expected_value STREQUAL CHSUM_VALUE) + message(FATAL_ERROR "Generated checksum is not valid! Expected [${expected_value}] Got [${CHSUM_VALUE}]") + endif() +else() + message(${error}) +endif() diff --git a/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt new file mode 100644 index 0000000..abf6d8c --- /dev/null +++ b/Tests/RunCMake/CPack/TGZ/PACKAGE_CHECKSUM-invalid-stderr.txt @@ -0,0 +1,2 @@ +^CPack Error: Cannot recognize algorithm: invalid +CPack Error: Error when generating package: package_checksum$ diff --git a/Tests/RunCMake/CPack/VerifyResult.cmake b/Tests/RunCMake/CPack/VerifyResult.cmake index 074890f..8bc2a58 100644 --- a/Tests/RunCMake/CPack/VerifyResult.cmake +++ b/Tests/RunCMake/CPack/VerifyResult.cmake @@ -8,10 +8,10 @@ file(READ "${bin_dir}/test_error.txt" error) file(READ "${config_file}" config_file_content) set(output_error_message - "\nCPack output: '${output}'\nCPack error: '${error}';\nconfig file: '${config_file_content}'") + "\nCPack output: '${output}'\nCPack error: '${error}';\nCPack result: '${PACKAGING_RESULT}';\nconfig file: '${config_file_content}'") # check that expected generated files exist and contain expected content -include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST}-ExpectedFiles.cmake") +include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST_FILE_PREFIX}-ExpectedFiles.cmake") if(NOT EXPECTED_FILES_COUNT EQUAL 0) foreach(file_no_ RANGE 1 ${EXPECTED_FILES_COUNT}) @@ -82,8 +82,8 @@ else() endif() # handle additional result verifications -if(EXISTS "${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST}-VerifyResult.cmake") - include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST}-VerifyResult.cmake") +if(EXISTS "${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST_FILE_PREFIX}-VerifyResult.cmake") + include("${src_dir}/${GENERATOR_TYPE}/${RunCMake_TEST_FILE_PREFIX}-VerifyResult.cmake") else() # by default only print out output and error so that they can be compared by # regex diff --git a/Tests/RunCMake/CommandLine/E_server-arg-result.txt b/Tests/RunCMake/CommandLine/E_server-arg-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_server-arg-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt b/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt new file mode 100644 index 0000000..4dcbab9 --- /dev/null +++ b/Tests/RunCMake/CommandLine/E_server-arg-stderr.txt @@ -0,0 +1 @@ +^CMake Error: Unknown argument for server mode$ diff --git a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake index 6ae47a8..9f76ad9 100644 --- a/Tests/RunCMake/CommandLine/RunCMakeTest.cmake +++ b/Tests/RunCMake/CommandLine/RunCMakeTest.cmake @@ -12,6 +12,7 @@ run_cmake_command(E_capabilities ${CMAKE_COMMAND} -E capabilities) run_cmake_command(E_capabilities-arg ${CMAKE_COMMAND} -E capabilities --extra-arg) run_cmake_command(E_echo_append ${CMAKE_COMMAND} -E echo_append) run_cmake_command(E_rename-no-arg ${CMAKE_COMMAND} -E rename) +run_cmake_command(E_server-arg ${CMAKE_COMMAND} -E server --extra-arg) run_cmake_command(E_touch_nocreate-no-arg ${CMAKE_COMMAND} -E touch_nocreate) run_cmake_command(E_time ${CMAKE_COMMAND} -E time ${CMAKE_COMMAND} -E echo "hello world") diff --git a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt index 96d0972..cd542d8 100644 --- a/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt +++ b/Tests/RunCMake/add_custom_command/AppendNotOutput-stderr.txt @@ -1,5 +1,8 @@ CMake Error at AppendNotOutput.cmake:1 \(add_custom_command\): - add_custom_command given APPEND option with output.* + add_custom_command given APPEND option with output + + .*RunCMake/add_custom_command/AppendNotOutput-build/out.* + which is not already a custom command output. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\) diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt new file mode 100644 index 0000000..247923b --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at DOWNLOAD-httpheader-not-set.cmake:[0-9]+ \(file\): + file DOWNLOAD missing string for HTTPHEADER. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake new file mode 100644 index 0000000..6efc958 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-httpheader-not-set.cmake @@ -0,0 +1 @@ +file(DOWNLOAD "" "" HTTPHEADER "Content-Type: application/x-compressed-tar" HTTPHEADER) diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt b/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-pass-not-set-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt b/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt new file mode 100644 index 0000000..2fa2731 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-pass-not-set-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at DOWNLOAD-pass-not-set.cmake:[0-9]+ \(file\): + file DOWNLOAD missing string for USERPWD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake b/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake new file mode 100644 index 0000000..61eff6d --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-pass-not-set.cmake @@ -0,0 +1 @@ +file(DOWNLOAD "" "" USERPWD) diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt b/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-unused-argument-result.txt diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt b/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt new file mode 100644 index 0000000..82a78c9 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-unused-argument-stderr.txt @@ -0,0 +1,5 @@ +^CMake Warning \(dev\) at DOWNLOAD-unused-argument.cmake:[0-9]+ \(file\): + Unexpected argument: JUNK +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it.$ diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake b/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake new file mode 100644 index 0000000..2e3fbe1 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-unused-argument.cmake @@ -0,0 +1,5 @@ +file(DOWNLOAD + "file://${CMAKE_CURRENT_SOURCE_DIR}/DOWNLOAD-unused-argument.txt" + "${CMAKE_CURRENT_BINARY_DIR}/unused-argument.txt" + JUNK + ) diff --git a/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt b/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/file/DOWNLOAD-unused-argument.txt diff --git a/Tests/RunCMake/file/LOCK-lowercase.cmake b/Tests/RunCMake/file/LOCK-lowercase.cmake new file mode 100644 index 0000000..373afda --- /dev/null +++ b/Tests/RunCMake/file/LOCK-lowercase.cmake @@ -0,0 +1,11 @@ +set(lock "${CMAKE_CURRENT_BINARY_DIR}/file-to-lock") + +if(WIN32) + string(TOLOWER ${lock} lock) +endif() + +file(LOCK ${lock} TIMEOUT 0) +file(LOCK ${lock} RELEASE) + +file(LOCK ${lock} TIMEOUT 0) +file(LOCK ${lock} RELEASE) diff --git a/Tests/RunCMake/file/RunCMakeTest.cmake b/Tests/RunCMake/file/RunCMakeTest.cmake index 5f85bba..48fa757 100644 --- a/Tests/RunCMake/file/RunCMakeTest.cmake +++ b/Tests/RunCMake/file/RunCMakeTest.cmake @@ -1,6 +1,12 @@ include(RunCMake) run_cmake(DOWNLOAD-hash-mismatch) +run_cmake(DOWNLOAD-unused-argument) +run_cmake(DOWNLOAD-httpheader-not-set) +run_cmake(DOWNLOAD-pass-not-set) +run_cmake(UPLOAD-unused-argument) +run_cmake(UPLOAD-httpheader-not-set) +run_cmake(UPLOAD-pass-not-set) run_cmake(INSTALL-DIRECTORY) run_cmake(INSTALL-MESSAGE-bad) run_cmake(FileOpenFailRead) @@ -18,6 +24,7 @@ run_cmake(LOCK-error-no-result-variable) run_cmake(LOCK-error-no-timeout) run_cmake(LOCK-error-timeout) run_cmake(LOCK-error-unknown-option) +run_cmake(LOCK-lowercase) run_cmake(GLOB) run_cmake(GLOB_RECURSE) # test is valid both for GLOB and GLOB_RECURSE diff --git a/Tests/RunCMake/file/UPLOAD-httpheader-not-set-result.txt b/Tests/RunCMake/file/UPLOAD-httpheader-not-set-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-httpheader-not-set-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/UPLOAD-httpheader-not-set-stderr.txt b/Tests/RunCMake/file/UPLOAD-httpheader-not-set-stderr.txt new file mode 100644 index 0000000..341baf5 --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-httpheader-not-set-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at UPLOAD-httpheader-not-set.cmake:[0-9]+ \(file\): + file UPLOAD missing string for HTTPHEADER. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/UPLOAD-httpheader-not-set.cmake b/Tests/RunCMake/file/UPLOAD-httpheader-not-set.cmake new file mode 100644 index 0000000..18d43cc --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-httpheader-not-set.cmake @@ -0,0 +1 @@ +file(UPLOAD "" "" HTTPHEADER "Content-Type: application/x-compressed-tar" HTTPHEADER) diff --git a/Tests/RunCMake/file/UPLOAD-pass-not-set-result.txt b/Tests/RunCMake/file/UPLOAD-pass-not-set-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-pass-not-set-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/file/UPLOAD-pass-not-set-stderr.txt b/Tests/RunCMake/file/UPLOAD-pass-not-set-stderr.txt new file mode 100644 index 0000000..089c0ad --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-pass-not-set-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at UPLOAD-pass-not-set.cmake:[0-9]+ \(file\): + file UPLOAD missing string for USERPWD. +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/file/UPLOAD-pass-not-set.cmake b/Tests/RunCMake/file/UPLOAD-pass-not-set.cmake new file mode 100644 index 0000000..4f3d86c --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-pass-not-set.cmake @@ -0,0 +1 @@ +file(UPLOAD "" "" USERPWD) diff --git a/Tests/RunCMake/file/UPLOAD-unused-argument-result.txt b/Tests/RunCMake/file/UPLOAD-unused-argument-result.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-unused-argument-result.txt diff --git a/Tests/RunCMake/file/UPLOAD-unused-argument-stderr.txt b/Tests/RunCMake/file/UPLOAD-unused-argument-stderr.txt new file mode 100644 index 0000000..3c1b744 --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-unused-argument-stderr.txt @@ -0,0 +1,5 @@ +^CMake Warning \(dev\) at UPLOAD-unused-argument.cmake:[0-9]+ \(file\): + Unexpected argument: JUNK +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\) +This warning is for project developers. Use -Wno-dev to suppress it.$ diff --git a/Tests/RunCMake/file/UPLOAD-unused-argument.cmake b/Tests/RunCMake/file/UPLOAD-unused-argument.cmake new file mode 100644 index 0000000..94ac9ac --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-unused-argument.cmake @@ -0,0 +1,5 @@ +file(UPLOAD + "${CMAKE_CURRENT_SOURCE_DIR}/UPLOAD-unused-argument.txt" + "file://${CMAKE_CURRENT_BINARY_DIR}/unused-argument.txt" + JUNK + ) diff --git a/Tests/RunCMake/file/UPLOAD-unused-argument.txt b/Tests/RunCMake/file/UPLOAD-unused-argument.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/file/UPLOAD-unused-argument.txt diff --git a/Tests/RunCMake/get_filename_component/KnownComponents.cmake b/Tests/RunCMake/get_filename_component/KnownComponents.cmake index d822258..7dfb55d 100644 --- a/Tests/RunCMake/get_filename_component/KnownComponents.cmake +++ b/Tests/RunCMake/get_filename_component/KnownComponents.cmake @@ -19,12 +19,12 @@ foreach(c DIRECTORY NAME EXT NAME_WE PATH) endforeach() # Test Windows paths with DIRECTORY component and an absolute Windows path. -get_filename_component(test_slashes "c:\\path\\to\\filename.ext.in" DIRECTORY) -check("DIRECTORY from backslashes" "${test_slashes}" "c:/path/to") +get_filename_component(test_slashes "C:\\path\\to\\filename.ext.in" DIRECTORY) +check("DIRECTORY from backslashes" "${test_slashes}" "C:/path/to") list(APPEND non_cache_vars test_slashes) -get_filename_component(test_winroot "c:\\filename.ext.in" DIRECTORY) -check("DIRECTORY in windows root" "${test_winroot}" "c:/") +get_filename_component(test_winroot "C:\\filename.ext.in" DIRECTORY) +check("DIRECTORY in windows root" "${test_winroot}" "C:/") list(APPEND non_cache_vars test_winroot) # Test finding absolute paths. @@ -33,8 +33,8 @@ check("ABSOLUTE" "${test_absolute}" "/path/to/filename.ext.in") get_filename_component(test_absolute "/../path/to/filename.ext.in" ABSOLUTE) check("ABSOLUTE .. in root" "${test_absolute}" "/path/to/filename.ext.in") -get_filename_component(test_absolute "c:/../path/to/filename.ext.in" ABSOLUTE) -check("ABSOLUTE .. in windows root" "${test_absolute}" "c:/path/to/filename.ext.in") +get_filename_component(test_absolute "C:/../path/to/filename.ext.in" ABSOLUTE) +check("ABSOLUTE .. in windows root" "${test_absolute}" "C:/path/to/filename.ext.in") list(APPEND non_cache_vars test_absolute) diff --git a/Tests/RunCMake/get_property/directory_properties-stderr.txt b/Tests/RunCMake/get_property/directory_properties-stderr.txt index 80c9877..6d5bcdb 100644 --- a/Tests/RunCMake/get_property/directory_properties-stderr.txt +++ b/Tests/RunCMake/get_property/directory_properties-stderr.txt @@ -3,4 +3,20 @@ get_property: --><-- get_directory_property: -->value<-- get_property: -->value<-- get_directory_property: --><-- -get_property: --><--$ +get_property: --><-- +get_directory_property: -->[^<;]*Tests/RunCMake/get_property/directory_properties<-- +get_property: -->[^<;]*Tests/RunCMake/get_property/directory_properties<-- +get_directory_property: -->[^<;]*Tests/RunCMake/get_property/directory_properties/sub1;[^<;]*Tests/RunCMake/get_property/directory_properties/sub2<-- +get_property: -->[^<;]*Tests/RunCMake/get_property/directory_properties/sub1;[^<;]*Tests/RunCMake/get_property/directory_properties/sub2<-- +get_directory_property: -->CustomTop;InterfaceTop<-- +get_property: -->CustomTop;InterfaceTop<-- +get_directory_property: -->CustomSub;InterfaceSub<-- +get_property: -->CustomSub;InterfaceSub<-- +get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build<-- +get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build<-- +get_directory_property: -->[^<;]*/RunCMake/get_property<-- +get_property: -->[^<;]*/Tests/RunCMake/get_property<-- +get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<-- +get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties-build/directory_properties<-- +get_directory_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<-- +get_property: -->[^<;]*/Tests/RunCMake/get_property/directory_properties<--$ diff --git a/Tests/RunCMake/get_property/directory_properties.cmake b/Tests/RunCMake/get_property/directory_properties.cmake index b0a9b1b..4e68738 100644 --- a/Tests/RunCMake/get_property/directory_properties.cmake +++ b/Tests/RunCMake/get_property/directory_properties.cmake @@ -13,3 +13,18 @@ set_directory_properties(PROPERTIES empty "" custom value) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" empty) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" custom) check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" noexist) + +add_custom_target(CustomTop) +add_library(InterfaceTop INTERFACE) +add_library(my::InterfaceTop ALIAS InterfaceTop) + +add_subdirectory(directory_properties) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" SUBDIRECTORIES) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" SUBDIRECTORIES) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" BUILDSYSTEM_TARGETS) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" BUILDSYSTEM_TARGETS) + +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" BINARY_DIR) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}" SOURCE_DIR) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" BINARY_DIR) +check_directory_property("${CMAKE_CURRENT_SOURCE_DIR}/directory_properties" SOURCE_DIR) diff --git a/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt new file mode 100644 index 0000000..7318b97 --- /dev/null +++ b/Tests/RunCMake/get_property/directory_properties/CMakeLists.txt @@ -0,0 +1,6 @@ +add_subdirectory(sub1) +subdirs(sub2) + +add_custom_target(CustomSub) +add_library(InterfaceSub INTERFACE) +add_library(my::InterfaceSub ALIAS InterfaceSub) diff --git a/Tests/RunCMake/get_property/directory_properties/sub1/CMakeLists.txt b/Tests/RunCMake/get_property/directory_properties/sub1/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/get_property/directory_properties/sub1/CMakeLists.txt diff --git a/Tests/RunCMake/get_property/directory_properties/sub2/CMakeLists.txt b/Tests/RunCMake/get_property/directory_properties/sub2/CMakeLists.txt new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/Tests/RunCMake/get_property/directory_properties/sub2/CMakeLists.txt diff --git a/Tests/Server/CMakeLists.txt b/Tests/Server/CMakeLists.txt new file mode 100644 index 0000000..8daf12a --- /dev/null +++ b/Tests/Server/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.4) +project(Server CXX) + +find_package(PythonInterp REQUIRED) + +macro(do_test bsname file) + execute_process(COMMAND ${PYTHON_EXECUTABLE} + "${CMAKE_SOURCE_DIR}/server-test.py" + "${CMAKE_COMMAND}" + "${CMAKE_SOURCE_DIR}/${file}" + "${CMAKE_SOURCE_DIR}" + "${CMAKE_BINARY_DIR}" + RESULT_VARIABLE test_result + ) + + if (NOT test_result EQUAL 0) + message(SEND_ERROR "TEST FAILED") + endif() +endmacro() + +do_test("test_handshake" "tc_handshake.json") + +add_executable(Server empty.cpp) diff --git a/Tests/Server/cmakelib.py b/Tests/Server/cmakelib.py new file mode 100644 index 0000000..e89b1f0 --- /dev/null +++ b/Tests/Server/cmakelib.py @@ -0,0 +1,126 @@ +import sys, subprocess, json + +termwidth = 150 + +print_communication = True + +def ordered(obj): + if isinstance(obj, dict): + return sorted((k, ordered(v)) for k, v in obj.items()) + if isinstance(obj, list): + return sorted(ordered(x) for x in obj) + else: + return obj + +def col_print(title, array): + print + print + print(title) + + indentwidth = 4 + indent = " " * indentwidth + + if not array: + print(indent + "<None>") + return + + padwidth = 2 + + maxitemwidth = len(max(array, key=len)) + + numCols = max(1, int((termwidth - indentwidth + padwidth) / (maxitemwidth + padwidth))) + + numRows = len(array) // numCols + 1 + + pad = " " * padwidth + + for index in range(numRows): + print(indent + pad.join(item.ljust(maxitemwidth) for item in array[index::numRows])) + +def waitForRawMessage(cmakeCommand): + stdoutdata = "" + payload = "" + while not cmakeCommand.poll(): + stdoutdataLine = cmakeCommand.stdout.readline() + if stdoutdataLine: + stdoutdata += stdoutdataLine.decode('utf-8') + else: + break + begin = stdoutdata.find("[== CMake Server ==[\n") + end = stdoutdata.find("]== CMake Server ==]") + + if (begin != -1 and end != -1): + begin += len("[== CMake Server ==[\n") + payload = stdoutdata[begin:end] + if print_communication: + print("\nSERVER>", json.loads(payload), "\n") + return json.loads(payload) + +def writeRawData(cmakeCommand, content): + writeRawData.counter += 1 + payload = """ +[== CMake Server ==[ +%s +]== CMake Server ==] +""" % content + + rn = ( writeRawData.counter % 2 ) == 0 + + if rn: + payload = payload.replace('\n', '\r\n') + + if print_communication: + print("\nCLIENT>", content, "(Use \\r\\n:", rn, ")\n") + cmakeCommand.stdin.write(payload.encode('utf-8')) + cmakeCommand.stdin.flush() +writeRawData.counter = 0 + +def writePayload(cmakeCommand, obj): + writeRawData(cmakeCommand, json.dumps(obj)) + +def initProc(cmakeCommand): + cmakeCommand = subprocess.Popen([cmakeCommand, "-E", "server", "--experimental"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE) + + packet = waitForRawMessage(cmakeCommand) + if packet == None: + print("Not in server mode") + sys.exit(1) + + if packet['type'] != 'hello': + print("No hello message") + sys.exit(1) + + return cmakeCommand + +def waitForMessage(cmakeCommand, expected): + data = ordered(expected) + packet = ordered(waitForRawMessage(cmakeCommand)) + + if packet != data: + sys.exit(-1) + return packet + +def waitForReply(cmakeCommand, originalType, cookie): + packet = waitForRawMessage(cmakeCommand) + if packet['cookie'] != cookie or packet['type'] != 'reply' or packet['inReplyTo'] != originalType: + sys.exit(1) + +def waitForError(cmakeCommand, originalType, cookie, message): + packet = waitForRawMessage(cmakeCommand) + if packet['cookie'] != cookie or packet['type'] != 'error' or packet['inReplyTo'] != originalType or packet['errorMessage'] != message: + sys.exit(1) + +def waitForProgress(cmakeCommand, originalType, cookie, current, message): + packet = waitForRawMessage(cmakeCommand) + if packet['cookie'] != cookie or packet['type'] != 'progress' or packet['inReplyTo'] != originalType or packet['progressCurrent'] != current or packet['progressMessage'] != message: + sys.exit(1) + +def handshake(cmakeCommand, major, minor): + version = { 'major': major } + if minor >= 0: + version['minor'] = minor + + writePayload(cmakeCommand, { 'type': 'handshake', 'protocolVersion': version, 'cookie': 'TEST_HANDSHAKE' }) + waitForReply(cmakeCommand, 'handshake', 'TEST_HANDSHAKE') diff --git a/Tests/Server/empty.cpp b/Tests/Server/empty.cpp new file mode 100644 index 0000000..766b775 --- /dev/null +++ b/Tests/Server/empty.cpp @@ -0,0 +1,5 @@ + +int main() +{ + return 0; +} diff --git a/Tests/Server/server-test.py b/Tests/Server/server-test.py new file mode 100644 index 0000000..e0a3b3b --- /dev/null +++ b/Tests/Server/server-test.py @@ -0,0 +1,82 @@ +import sys, cmakelib, json + +debug = True + +cmakeCommand = sys.argv[1] +testFile = sys.argv[2] +sourceDir = sys.argv[3] +buildDir = sys.argv[4] + +print("SourceDir: ", sourceDir, " -- BuildDir: ", buildDir) + +proc = cmakelib.initProc(cmakeCommand) + +with open(testFile) as f: + testText = f.read() + testText = testText.replace('%BUILDDIR%', buildDir) + testText = testText.replace('%SOURCEDIR%', sourceDir) + testData = json.loads(testText) + +buildDir = sys.argv[3] +sourceDir = sys.argv[4] + +for obj in testData: + if 'sendRaw' in obj: + data = obj['sendRaw'] + if debug: print("Sending raw:", data) + cmakelib.writeRawData(proc, data) + elif 'send' in obj: + data = obj['send'] + if debug: print("Sending:", json.dumps(data)) + cmakelib.writePayload(proc, data) + elif 'recv' in obj: + data = obj['recv'] + if debug: print("Waiting for:", json.dumps(data)) + cmakelib.waitForMessage(proc, data) + elif 'reply' in obj: + data = obj['reply'] + if debug: print("Waiting for reply:", json.dumps(data)) + originalType = "" + cookie = "" + if 'cookie' in data: cookie = data['cookie'] + if 'type' in data: originalType = data['type'] + cmakelib.waitForReply(proc, originalType, cookie) + elif 'error' in obj: + data = obj['error'] + if debug: print("Waiting for error:", json.dumps(data)) + originalType = "" + cookie = "" + message = "" + if 'cookie' in data: cookie = data['cookie'] + if 'type' in data: originalType = data['type'] + if 'message' in data: message = data['message'] + cmakelib.waitForError(proc, originalType, cookie, message) + elif 'progress' in obj: + data = obj['progress'] + if debug: print("Waiting for progress:", json.dumps(data)) + originalType = '' + cookie = "" + current = 0 + message = "" + if 'cookie' in data: cookie = data['cookie'] + if 'type' in data: originalType = data['type'] + if 'current' in data: current = data['current'] + if 'message' in data: message = data['message'] + cmakelib.waitForProgress(proc, originalType, cookie, current, message) + elif 'handshake' in obj: + data = obj['handshake'] + if debug: print("Doing handshake:", json.dumps(data)) + major = -1 + minor = -1 + if 'major' in data: major = data['major'] + if 'minor' in data: minor = data['minor'] + cmakelib.handshake(proc, major, minor) + elif 'message' in obj: + print("MESSAGE:", obj["message"]) + else: + print("Unknown command:", json.dumps(obj)) + sys.exit(2) + + print("Completed") + +sys.exit(0) diff --git a/Tests/Server/tc_handshake.json b/Tests/Server/tc_handshake.json new file mode 100644 index 0000000..5261581 --- /dev/null +++ b/Tests/Server/tc_handshake.json @@ -0,0 +1,71 @@ +[ +{ "message": "Testing basic message handling:" }, + +{ "sendRaw": "Sometext"}, +{ "recv": {"cookie":"","errorMessage":"Failed to parse JSON input.","inReplyTo":"","type":"error"} }, + +{ "message": "Testing invalid json input"}, +{ "send": { "test": "sometext" } }, +{ "recv": {"cookie":"","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} }, + +{ "send": {"test": "sometext","cookie":"monster"} }, +{ "recv": {"cookie":"monster","errorMessage":"No type given in request.","inReplyTo":"","type":"error"} }, + +{ "message": "Testing handshake" }, +{ "send": {"type": "sometype","cookie":"monster2"} }, +{ "recv": {"cookie":"monster2","errorMessage":"Waiting for type \"handshake\".","inReplyTo":"sometype","type":"error"} }, + +{ "send": {"type": "handshake"} }, +{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","foo":"bar"} }, +{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" is required for \"handshake\".","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":"bar"} }, +{ "recv": {"cookie":"","errorMessage":"\"protocolVersion\" must be a JSON object.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{}} }, +{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":"foo"}} }, +{ "recv": {"cookie":"","errorMessage":"\"major\" must be set and an integer.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":"foo"}} }, +{ "recv": {"cookie":"","errorMessage":"\"minor\" must be unset or an integer.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":-1, "minor":-1}} }, +{ "recv": {"cookie":"","errorMessage":"\"major\" must be >= 0.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":10, "minor":-1}} }, +{ "recv": {"cookie":"","errorMessage":"\"minor\" must be >= 0 when set.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":10000}} }, +{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"type": "handshake","protocolVersion":{"major":1, "minor":10000}} }, +{ "recv": {"cookie":"","errorMessage":"Protocol version not supported.","inReplyTo":"handshake","type":"error"} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1}} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} }, + +{ "message": "Testing protocol version specific options (1.0):" }, +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"buildDirectory\" is missing."} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":"/tmp/src","buildDirectory":"/tmp/build"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"sourceDirectory\" is not a directory."} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","extraGenerator":"CodeBlocks"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: \"generator\" is unset but required."} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"XXXX","extraGenerator":"CodeBlocks"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: Could not set up the requested combination of \"generator\" and \"extraGenerator\""} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"XXXX"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"error","errorMessage":"Failed to activate protocol version: Could not set up the requested combination of \"generator\" and \"extraGenerator\""} }, + +{ "send": {"cookie":"zimtstern","type": "handshake","protocolVersion":{"major":1},"sourceDirectory":".","buildDirectory":"/tmp/build","generator":"Ninja","extraGenerator":"CodeBlocks"} }, +{ "recv": {"cookie":"zimtstern","inReplyTo":"handshake","type":"reply"} }, + +{ "message": "Everything ok." } +] diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt index 6ebf2b4..add5326 100644 --- a/Utilities/Doxygen/CMakeLists.txt +++ b/Utilities/Doxygen/CMakeLists.txt @@ -12,7 +12,7 @@ if(NOT CMake_SOURCE_DIR) set(CMakeDeveloperReference_STANDALONE 1) - cmake_minimum_required(VERSION 2.8.4 FATAL_ERROR) + cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake index 168eb86..e7e154e 100644 --- a/Utilities/Release/linux64_release.cmake +++ b/Utilities/Release/linux64_release.cmake @@ -21,7 +21,7 @@ set(qt_xcb_libs set(INITIAL_CACHE " CMAKE_BUILD_TYPE:STRING=Release CMAKE_C_STANDARD:STRING=11 -CMAKE_CXX_STANDARD:STRING=11 +CMAKE_CXX_STANDARD:STRING=14 CMAKE_C_FLAGS:STRING=-D_POSIX_C_SOURCE=199506L -D_POSIX_SOURCE=1 -D_SVID_SOURCE=1 -D_BSD_SOURCE=1 CMAKE_EXE_LINKER_FLAGS:STRING=-static-libstdc++ -static-libgcc CURSES_LIBRARY:FILEPATH=/home/kitware/ncurses-5.9/lib/libncurses.a diff --git a/Utilities/Release/osx_release.cmake b/Utilities/Release/osx_release.cmake index e7e5ba4..12b12d7 100644 --- a/Utilities/Release/osx_release.cmake +++ b/Utilities/Release/osx_release.cmake @@ -14,7 +14,7 @@ set(CXXFLAGS "-stdlib=libc++") set(INITIAL_CACHE " CMAKE_BUILD_TYPE:STRING=Release CMAKE_C_STANDARD:STRING=11 -CMAKE_CXX_STANDARD:STRING=11 +CMAKE_CXX_STANDARD:STRING=14 CMAKE_OSX_ARCHITECTURES:STRING=x86_64 CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.7 CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE diff --git a/Utilities/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake index a27efda..f54a4ca 100644 --- a/Utilities/Release/win32_release.cmake +++ b/Utilities/Release/win32_release.cmake @@ -27,6 +27,6 @@ get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. - set(EXTRA_CTEST_ARGS "-E Qt5Autogen") + set(EXTRA_CTEST_ARGS "-E 'Qt5Autogen|ConsoleBuf'") endif() include(${path}/release_cmake.cmake) diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake index e39a610..bd2690f 100644 --- a/Utilities/Release/win64_release.cmake +++ b/Utilities/Release/win64_release.cmake @@ -28,6 +28,6 @@ get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH) set(GIT_EXTRA "git config core.autocrlf true") if(CMAKE_CREATE_VERSION STREQUAL "nightly") # Some tests fail spuriously too often. - set(EXTRA_CTEST_ARGS "-E Qt5Autogen") + set(EXTRA_CTEST_ARGS "-E 'Qt5Autogen|ConsoleBuf'") endif() include(${path}/release_cmake.cmake) diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt index 45f79dd..be4850e 100644 --- a/Utilities/Sphinx/CMakeLists.txt +++ b/Utilities/Sphinx/CMakeLists.txt @@ -11,7 +11,7 @@ #============================================================================= if(NOT CMake_SOURCE_DIR) set(CMakeHelp_STANDALONE 1) - cmake_minimum_required(VERSION 2.8.4 FATAL_ERROR) + cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR) get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH) get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH) include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake) |