diff options
96 files changed, 1764 insertions, 776 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 472c6ab..ed5de10 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -806,6 +806,7 @@ if(NOT CMake_TEST_EXTERNAL_CMAKE) PATTERN "*.sh*" PERMISSIONS OWNER_READ OWNER_EXECUTE OWNER_WRITE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE + REGEX "Help/dev($|/)" EXCLUDE ) # Install auxiliary files integrating with other tools. diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 921ba7c..434f0f4 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,6 +1,11 @@ Contributing to CMake ********************* +The following summarizes the process for contributing changes. +See documentation on `CMake Development`_ for more information. + +.. _`CMake Development`: Help/dev/README.rst + Community ========= @@ -19,13 +24,18 @@ CMake uses `Kitware's GitLab Instance`_ to manage development and code review. To contribute patches: #. Fork the upstream `CMake Repository`_ into a personal account. +#. Run `Utilities/SetupForDevelopment.sh`_ for local configuration. #. Base all new work on the upstream ``master`` branch. #. Create commits making incremental, distinct, logically complete changes. #. Push a topic branch to a personal repository fork on GitLab. #. Create a GitLab Merge Request targeting the upstream ``master`` branch. +The merge request will enter the `CMake Review Process`_ for consideration. + .. _`Kitware's GitLab Instance`: https://gitlab.kitware.com .. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake +.. _`Utilities/SetupForDevelopment.sh`: Utilities/SetupForDevelopment.sh +.. _`CMake Review Process`: Help/dev/review.rst Code Style ========== diff --git a/Help/dev/README.rst b/Help/dev/README.rst new file mode 100644 index 0000000..0dc512a --- /dev/null +++ b/Help/dev/README.rst @@ -0,0 +1,31 @@ +CMake Development +***************** + +This directory contains documentation about development of CMake itself. +It is not part of the user documentation distributed with CMake. + +Contributor Instructions +======================== + +See `CONTRIBUTING.rst`_ for instructions to contribute changes. + +The process for contributing changes is the same whether or not one +has been invited to participate directly in upstream development. + +.. _`CONTRIBUTING.rst`: ../../CONTRIBUTING.rst + +Upstream Development +==================== + +CMake uses `Kitware's GitLab Instance`_ to manage development, review, and +integration of changes. The `CMake Repository`_ holds the integration +branches and tags. Upstream development processes are covered by the +following documents: + +* The `CMake Review Process`_ manages integration of changes. +* The `CMake Testing Process`_ drives integration testing. + +.. _`Kitware's GitLab Instance`: https://gitlab.kitware.com +.. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake +.. _`CMake Review Process`: review.rst +.. _`CMake Testing Process`: testing.rst diff --git a/Help/dev/review.rst b/Help/dev/review.rst new file mode 100644 index 0000000..e23c0fb --- /dev/null +++ b/Help/dev/review.rst @@ -0,0 +1,306 @@ +CMake Review Process +******************** + +The following documents the process for reviewing and integrating changes. +See `CONTRIBUTING.rst`_ for instructions to contribute changes. +See documentation on `CMake Development`_ for more information. + +.. _`CONTRIBUTING.rst`: ../../CONTRIBUTING.rst +.. _`CMake Development`: README.rst + +.. contents:: The review process consists of the following steps: + +Merge Request +============= + +A user initiates the review process for a change by pushing a *topic +branch* to his or her own fork of the `CMake Repository`_ on GitLab and +creating a *merge request* ("MR"). The new MR will appear on the +`CMake Merge Requests Page`_. The rest of the review and integration +process is managed by the merge request page for the change. + +During the review process, the MR submitter should address review comments +or test failures by updating the MR with a (force-)push of the topic +branch. The update initiates a new round of review. + +We recommend that users enable the "Remove source branch when merge +request is accepted" option when creating the MR or by editing it. +This will cause the MR topic branch to be automatically removed from +the user's fork during the `Merge`_ step. + +.. _`CMake Merge Requests Page`: https://gitlab.kitware.com/cmake/cmake/merge_requests +.. _`CMake Repository`: https://gitlab.kitware.com/cmake/cmake + +Workflow Status +--------------- + +`CMake GitLab Project Developers`_ may set one of the following labels +in GitLab to track the state of a MR: + +* ``workflow:wip`` indicates that the MR needs additional updates from + the MR submitter before further review. Use this label after making + comments that require such updates. + +* ``workflow:in-review`` indicates that the MR awaits feedback from a + human reviewer or from `Topic Testing`_. Use this label after making + comments requesting such feedback. + +* ``workflow:nightly-testing`` indicates that the MR awaits results + of `Integration Testing`_. Use this label after making comments + requesting such staging. + +* ``workflow:expired`` indicates that the MR has been closed due + to a period of inactivity. See the `Expire`_ step. Use this label + after closing a MR for this reason. + +The workflow status labels are intended to be mutually exclusive, +so please remove any existing workflow label when adding one. + +.. _`CMake GitLab Project Developers`: https://gitlab.kitware.com/cmake/cmake/settings/members + +Robot Review +============ + +The "Kitware Robot" (``@kwrobot``) automatically performs basic checks on +the commits proposed in a MR. If all is well the robot silently reports +a successful "build" status to GitLab. Otherwise the robot posts a comment +with its diagnostics. **A topic may not be merged until the automatic +review succeeds.** The MR submitter is expected to address the robot's +comments by *rewriting* the commits named by the robot's diagnostics +(e.g. via ``git rebase -i``). + +The automatic check is repeated whenever the topic branch is updated. +One may explicitly request a re-check by adding a comment with the +following command among the `comment trailing lines`_:: + + Do: check + +``@kwrobot`` will add an award emoji to the comment to indicate that it +was processed and also run its checks again. + +Human Review +============ + +Anyone is welcome to review merge requests and make comments! + +Reviewers may add comments providing feedback or to acknowledge their +approval. Lines of specific forms will be extracted during the `merge`_ +step and included as trailing lines of the generated merge commit message. +Each review comment consists of up to two parts which must be specified +in the following order: `comment body`_, then `comment trailing lines`_. +Each part is optional, but they must be specified in this order. + +Comment Body +------------ + +The body of a comment may be free-form `GitLab Flavored Markdown`_. +See GitLab documentation on `Special GitLab References`_ to add links to +things like issues, commits, or other merge requests (even across projects). + +Additionally, a line in the comment body may start with one of the +following votes: + +* ``-1`` or ``:-1:`` indicates "the change is not ready for integration". + +* ``+1`` or ``:+1:`` indicates "I like the change". + This adds an ``Acked-by:`` trailer to the `merge`_ commit message. + +* ``+2`` indicates "the change is ready for integration". + This adds a ``Reviewed-by:`` trailer to the `merge`_ commit message. + +* ``+3`` indicates "I have tested the change and verified it works". + This adds a ``Tested-by:`` trailer to the `merge`_ commit message. + +.. _`GitLab Flavored Markdown`: https://gitlab.kitware.com/help/user/markdown.md +.. _`Special GitLab References`: https://gitlab.kitware.com/help/user/markdown.md#special-gitlab-references + +Comment Trailing Lines +---------------------- + +Zero or more *trailing* lines in the last section of a comment may appear +with the form ``Key: Value``. The first such line should be separated +from a preceding `comment body`_ by a blank line. Any key-value pair(s) +may be specified for human reference. A few specific keys have meaning to +``@kwrobot`` as follows. + +Comment Trailer Votes +^^^^^^^^^^^^^^^^^^^^^ + +Among the `comment trailing lines`_ one may cast a vote using one of the +following pairs followed by nothing but whitespace before the end of the line: + +* ``Rejected-by: me`` indicates "the change is not ready for integration". +* ``Acked-by: me`` indicates "I like the change". + This adds an ``Acked-by:`` trailer to the `merge`_ commit message. +* ``Reviewed-by: me`` indicates "the change is ready for integration". + This adds a ``Reviewed-by:`` trailer to the `merge`_ commit message. +* ``Tested-by: me`` indicates "I have tested the change and verified it works". + This adds a ``Tested-by:`` trailer to the `merge`_ commit message. + +Each ``me`` reference may instead be an ``@username`` reference or a full +``Real Name <user@domain>`` reference to credit someone else for performing +the review. References to ``me`` and ``@username`` will automatically be +transformed into a real name and email address according to the user's +GitLab account profile. + +Comment Trailer Commands +^^^^^^^^^^^^^^^^^^^^^^^^ + +Among the `comment trailing lines`_ authorized users may issue special +commands to ``@kwrobot`` using the form ``Do: ...``: + +* ``Do: check`` explicitly re-runs `Robot Review`_ checks. +* ``Do: test`` submits the MR for `Topic Testing`_. +* ``Do: stage`` submits the MR for `Integration Testing`_. +* ``Do: merge`` submits the MR for `Merge`_. + +See the corresponding sections for details on permissions and options +for each command. + +Topic Testing +============= + +CMake has a `buildbot`_ instance watching for merge requests to test. +`CMake GitLab Project Developers`_ may activate buildbot on a MR by +adding a comment with a command among the `comment trailing lines`_:: + + Do: test + +``@kwrobot`` will add an award emoji to the comment to indicate that it +was processed and also inform buildbot about the request. The buildbot +user (``@buildbot``) will schedule builds and respond with a comment +linking to the `CMake CDash Page`_ with a filter for results associated +with the topic test request. If the MR topic branch is updated by a +push a new ``Do: test`` command is needed to activate testing again. + +The ``Do: test`` command accepts the following arguments: + +* ``--stop``: clear the list of commands for the merge request +* ``--clear``: clear previous commands before adding this command +* ``--regex-include <arg>`` or ``-i <arg>``: only build on builders + matching ``<arg>`` (a Python regular expression) +* ``--regex-exclude <arg>`` or ``-e <arg>``: exclude builds on builders + matching ``<arg>`` (a Python regular expression) + +Builder names follow the pattern ``project-host-os-buildtype-generator``: + +* ``project``: always ``cmake`` for CMake builds +* ``host``: the buildbot host +* ``os``: one of ``windows``, ``osx``, or ``linux`` +* ``buildtype``: ``release`` or ``debug`` +* ``generator``: ``ninja``, ``makefiles``, or ``vs<year>`` + +.. _`buildbot`: http://buildbot.net +.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake + +Integration Testing +=================== + +The above `topic testing`_ tests the MR topic independent of other +merge requests and on only a few key platforms and configurations. +The `CMake Testing Process`_ also has a large number of machines +provided by Kitware and generous volunteers that cover nearly all +supported platforms, generators, and configurations. In order to +avoid overwhelming these resources, they do not test every MR +individually. Instead, these machines follow an *integration branch*, +run tests on a nightly basis (or continuously during the day), and +post to the `CMake CDash Page`_. Some follow ``master``. Most follow +a special integration branch, the *topic stage*. + +The topic stage is a special branch maintained by the "Kitware Robot" +(``@kwrobot``). It consists of the head of the MR target integration +branch (e.g. ``master``) branch followed by a sequence of merges each +integrating changes from an open MR that has been staged for integration +testing. Each time the target integration branch is updated the stage +is rebuilt automatically by merging the staged MR topics again. + +`CMake GitLab Project Developers`_ may stage a MR for integration testing +by adding a comment with a command among the `comment trailing lines`_:: + + Do: stage + +``@kwrobot`` will add an award emoji to the comment to indicate that it +was processed and also attempt to add the MR topic branch to the topic +stage. If the MR cannot be added (e.g. due to conflicts) the robot will +post a comment explaining what went wrong. + +Once a MR has been added to the topic stage it will remain on the stage +until one of the following occurs: + +* The MR topic branch is updated by a push. + +* The MR target integration branch (e.g. ``master``) branch is updated + and the MR cannot be merged into the topic stage again due to conflicts. + +* A developer or the submitter posts an explicit ``Do: unstage`` command. + +* The MR is closed. + +* The MR is merged. + +Once a MR has been removed from the topic stage a new ``Do: stage`` +command is needed to stage it again. + +.. _`CMake Testing Process`: testing.rst + +Resolve +======= + +A MR may be resolved in one of the following ways. + +Merge +----- + +Once review has concluded that the MR topic is ready for integration, +`CMake GitLab Project Masters`_ may merge the topic by adding a comment +with a command among the `comment trailing lines`_:: + + Do: merge + +``@kwrobot`` will add an award emoji to the comment to indicate that it +was processed and also attempt to merge the MR topic branch to the MR +target integration branch (e.g. ``master``). If the MR cannot be merged +(e.g. due to conflicts) the robot will post a comment explaining what +went wrong. If the MR is merged the robot will also remove the source +branch from the user's fork if the corresponding MR option was checked. + +The robot automatically constructs a merge commit message of the following +form:: + + Merge topic 'mr-topic-branch-name' + + 00000000 commit message subject line (one line per commit) + + Acked-by: Kitware Robot <kwrobot@kitware.com> + Merge-request: !0000 + +Mention of the commit short sha1s and MR number helps GitLab link the +commits back to the merge request and indicates when they were merged. +The ``Acked-by:`` trailer shown indicates that `Robot Review`_ passed. +Additional ``Acked-by:``, ``Reviewed-by:``, and similar trailers may be +collected from `Human Review`_ comments that have been made since the +last time the MR topic branch was updated with a push. + +The ``Do: merge`` command accepts the following arguments: + +* ``-t <topic>``: substitute ``<topic>`` for the name of the MR topic + branch in the constructed merge commit message. + +.. _`CMake GitLab Project Masters`: https://gitlab.kitware.com/cmake/cmake/settings/members + +Close +----- + +If review has concluded that the MR should not be integrated then it +may be closed through GitLab. + +Expire +------ + +If progress on a MR has stalled for a while, it may be closed with a +``workflow:expired`` label and a comment indicating that the MR has +been closed due to inactivity. + +Contributors are welcome to re-open an expired MR when they are ready +to continue work. Please re-open *before* pushing an update to the +MR topic branch to ensure GitLab will still act on the association. diff --git a/Help/dev/testing.rst b/Help/dev/testing.rst new file mode 100644 index 0000000..731930c --- /dev/null +++ b/Help/dev/testing.rst @@ -0,0 +1,42 @@ +CMake Testing Process +********************* + +The following documents the process for running integration testing builds. +See documentation on `CMake Development`_ for more information. + +.. _`CMake Development`: README.rst + +CMake Dashboard Scripts +======================= + +The *integration testing* step of the `CMake Review Process`_ uses a set of +testing machines that follow an integration branch on their own schedule to +drive testing and submit results to the `CMake CDash Page`_. Anyone is +welcome to provide testing machines in order to help keep support for their +platforms working. + +The `CMake Dashboard Scripts Repository`_ provides CTest scripts to drive +nightly, continous, and experimental testing of CMake. Use the following +commands to set up a new integration testing client: + +.. code-block:: console + + $ mkdir -p ~/Dashboards + $ cd ~/Dashboards + $ git clone https://gitlab.kitware.com/cmake/dashboard-scripts.git CMakeScripts + $ cd CMakeScripts + +The ``cmake_common.cmake`` script contains comments at the top with +instructions to set up a testing client. As it instructs, create a +CTest script with local settings and include ``cmake_common.cmake``. + +.. _`CMake Review Process`: review.rst +.. _`CMake CDash Page`: https://open.cdash.org/index.php?project=CMake +.. _`CMake Dashboard Scripts Repository`: https://gitlab.kitware.com/cmake/dashboard-scripts + +Nightly Start Time +------------------ + +The ``cmake_common.cmake`` script expects its includer to be run from a +nightly scheduled task (cron job). Schedule such tasks for sometime after +``1:00am UTC``, the time at which our nightly testing branches fast-forward. diff --git a/Help/manual/cmake-variables.7.rst b/Help/manual/cmake-variables.7.rst index 79c7cd8..3ec0c19 100644 --- a/Help/manual/cmake-variables.7.rst +++ b/Help/manual/cmake-variables.7.rst @@ -13,9 +13,9 @@ Variables that Provide Information .. toctree:: :maxdepth: 1 + /variable/CMAKE_AR /variable/CMAKE_ARGC /variable/CMAKE_ARGV0 - /variable/CMAKE_AR /variable/CMAKE_BINARY_DIR /variable/CMAKE_BUILD_TOOL /variable/CMAKE_CACHEFILE_DIR @@ -85,15 +85,15 @@ Variables that Provide Information /variable/CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE /variable/CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION /variable/CMAKE_XCODE_PLATFORM_TOOLSET - /variable/PROJECT_BINARY_DIR /variable/PROJECT-NAME_BINARY_DIR - /variable/PROJECT_NAME /variable/PROJECT-NAME_SOURCE_DIR /variable/PROJECT-NAME_VERSION /variable/PROJECT-NAME_VERSION_MAJOR /variable/PROJECT-NAME_VERSION_MINOR /variable/PROJECT-NAME_VERSION_PATCH /variable/PROJECT-NAME_VERSION_TWEAK + /variable/PROJECT_BINARY_DIR + /variable/PROJECT_NAME /variable/PROJECT_SOURCE_DIR /variable/PROJECT_VERSION /variable/PROJECT_VERSION_MAJOR @@ -127,7 +127,6 @@ Variables that Change Behavior /variable/CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION /variable/CMAKE_EXPORT_COMPILE_COMMANDS /variable/CMAKE_EXPORT_NO_PACKAGE_REGISTRY - /variable/CMAKE_SYSROOT /variable/CMAKE_FIND_APPBUNDLE /variable/CMAKE_FIND_FRAMEWORK /variable/CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX @@ -144,9 +143,9 @@ Variables that Change Behavior /variable/CMAKE_FIND_ROOT_PATH_MODE_PROGRAM /variable/CMAKE_FRAMEWORK_PATH /variable/CMAKE_IGNORE_PATH - /variable/CMAKE_INCLUDE_PATH /variable/CMAKE_INCLUDE_DIRECTORIES_BEFORE /variable/CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE + /variable/CMAKE_INCLUDE_PATH /variable/CMAKE_INSTALL_DEFAULT_COMPONENT_NAME /variable/CMAKE_INSTALL_MESSAGE /variable/CMAKE_INSTALL_PREFIX @@ -164,6 +163,7 @@ Variables that Change Behavior /variable/CMAKE_STAGING_PREFIX /variable/CMAKE_SUBLIME_TEXT_2_ENV_SETTINGS /variable/CMAKE_SUBLIME_TEXT_2_EXCLUDE_BUILD_TREE + /variable/CMAKE_SYSROOT /variable/CMAKE_SYSTEM_APPBUNDLE_PATH /variable/CMAKE_SYSTEM_FRAMEWORK_PATH /variable/CMAKE_SYSTEM_IGNORE_PATH @@ -188,23 +188,24 @@ Variables that Describe the System /variable/CMAKE_COMPILER_2005 /variable/CMAKE_HOST_APPLE /variable/CMAKE_HOST_SOLARIS + /variable/CMAKE_HOST_SYSTEM /variable/CMAKE_HOST_SYSTEM_NAME /variable/CMAKE_HOST_SYSTEM_PROCESSOR - /variable/CMAKE_HOST_SYSTEM /variable/CMAKE_HOST_SYSTEM_VERSION /variable/CMAKE_HOST_UNIX /variable/CMAKE_HOST_WIN32 - /variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX /variable/CMAKE_LIBRARY_ARCHITECTURE + /variable/CMAKE_LIBRARY_ARCHITECTURE_REGEX /variable/CMAKE_OBJECT_PATH_MAX + /variable/CMAKE_SYSTEM /variable/CMAKE_SYSTEM_NAME /variable/CMAKE_SYSTEM_PROCESSOR - /variable/CMAKE_SYSTEM /variable/CMAKE_SYSTEM_VERSION /variable/CYGWIN /variable/ENV /variable/GHS-MULTI /variable/MINGW + /variable/MSVC /variable/MSVC10 /variable/MSVC11 /variable/MSVC12 @@ -215,7 +216,6 @@ Variables that Describe the System /variable/MSVC80 /variable/MSVC90 /variable/MSVC_IDE - /variable/MSVC /variable/MSVC_VERSION /variable/UNIX /variable/WIN32 @@ -257,9 +257,9 @@ Variables that Control the Build /variable/CMAKE_ANDROID_STL_TYPE /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY /variable/CMAKE_ARCHIVE_OUTPUT_DIRECTORY_CONFIG + /variable/CMAKE_AUTOMOC /variable/CMAKE_AUTOMOC_DEPEND_FILTERS /variable/CMAKE_AUTOMOC_MOC_OPTIONS - /variable/CMAKE_AUTOMOC /variable/CMAKE_AUTORCC /variable/CMAKE_AUTORCC_OPTIONS /variable/CMAKE_AUTOUIC @@ -273,18 +273,19 @@ Variables that Control the Build /variable/CMAKE_CONFIG_POSTFIX /variable/CMAKE_DEBUG_POSTFIX /variable/CMAKE_ENABLE_EXPORTS + /variable/CMAKE_EXE_LINKER_FLAGS /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG /variable/CMAKE_EXE_LINKER_FLAGS_CONFIG_INIT - /variable/CMAKE_EXE_LINKER_FLAGS /variable/CMAKE_EXE_LINKER_FLAGS_INIT /variable/CMAKE_Fortran_FORMAT /variable/CMAKE_Fortran_MODULE_DIRECTORY /variable/CMAKE_GNUtoMS - /variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE /variable/CMAKE_INCLUDE_CURRENT_DIR + /variable/CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE /variable/CMAKE_INSTALL_NAME_DIR /variable/CMAKE_INSTALL_RPATH /variable/CMAKE_INSTALL_RPATH_USE_LINK_PATH + /variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION /variable/CMAKE_IOS_INSTALL_COMBINED /variable/CMAKE_LANG_CLANG_TIDY /variable/CMAKE_LANG_COMPILER_LAUNCHER @@ -303,9 +304,9 @@ Variables that Control the Build /variable/CMAKE_MACOSX_BUNDLE /variable/CMAKE_MACOSX_RPATH /variable/CMAKE_MAP_IMPORTED_CONFIG_CONFIG + /variable/CMAKE_MODULE_LINKER_FLAGS /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG /variable/CMAKE_MODULE_LINKER_FLAGS_CONFIG_INIT - /variable/CMAKE_MODULE_LINKER_FLAGS /variable/CMAKE_MODULE_LINKER_FLAGS_INIT /variable/CMAKE_NINJA_OUTPUT_PATH_PREFIX /variable/CMAKE_NO_BUILTIN_CHRPATH @@ -318,15 +319,15 @@ Variables that Control the Build /variable/CMAKE_POSITION_INDEPENDENT_CODE /variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY /variable/CMAKE_RUNTIME_OUTPUT_DIRECTORY_CONFIG + /variable/CMAKE_SHARED_LINKER_FLAGS /variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG /variable/CMAKE_SHARED_LINKER_FLAGS_CONFIG_INIT - /variable/CMAKE_SHARED_LINKER_FLAGS /variable/CMAKE_SHARED_LINKER_FLAGS_INIT /variable/CMAKE_SKIP_BUILD_RPATH /variable/CMAKE_SKIP_INSTALL_RPATH + /variable/CMAKE_STATIC_LINKER_FLAGS /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG /variable/CMAKE_STATIC_LINKER_FLAGS_CONFIG_INIT - /variable/CMAKE_STATIC_LINKER_FLAGS /variable/CMAKE_STATIC_LINKER_FLAGS_INIT /variable/CMAKE_TRY_COMPILE_CONFIGURATION /variable/CMAKE_TRY_COMPILE_PLATFORM_VARIABLES @@ -335,8 +336,8 @@ Variables that Control the Build /variable/CMAKE_VISIBILITY_INLINES_HIDDEN /variable/CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD /variable/CMAKE_VS_INCLUDE_PACKAGE_TO_DEFAULT_BUILD - /variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS /variable/CMAKE_WIN32_EXECUTABLE + /variable/CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS /variable/CMAKE_XCODE_ATTRIBUTE_an-attribute /variable/EXECUTABLE_OUTPUT_PATH /variable/LIBRARY_OUTPUT_PATH @@ -350,10 +351,6 @@ Variables for Languages /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 - /variable/CMAKE_C_STANDARD_REQUIRED /variable/CMAKE_CUDA_EXTENSIONS /variable/CMAKE_CUDA_STANDARD /variable/CMAKE_CUDA_STANDARD_REQUIRED @@ -362,6 +359,10 @@ Variables for Languages /variable/CMAKE_CXX_EXTENSIONS /variable/CMAKE_CXX_STANDARD /variable/CMAKE_CXX_STANDARD_REQUIRED + /variable/CMAKE_C_COMPILE_FEATURES + /variable/CMAKE_C_EXTENSIONS + /variable/CMAKE_C_STANDARD + /variable/CMAKE_C_STANDARD_REQUIRED /variable/CMAKE_Fortran_MODDIR_DEFAULT /variable/CMAKE_Fortran_MODDIR_FLAG /variable/CMAKE_Fortran_MODOUT_FLAG @@ -372,27 +373,27 @@ Variables for Languages /variable/CMAKE_LANG_ARCHIVE_APPEND /variable/CMAKE_LANG_ARCHIVE_CREATE /variable/CMAKE_LANG_ARCHIVE_FINISH - /variable/CMAKE_LANG_COMPILE_OBJECT + /variable/CMAKE_LANG_COMPILER /variable/CMAKE_LANG_COMPILER_ABI + /variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN /variable/CMAKE_LANG_COMPILER_ID /variable/CMAKE_LANG_COMPILER_LOADED - /variable/CMAKE_LANG_COMPILER - /variable/CMAKE_LANG_COMPILER_EXTERNAL_TOOLCHAIN /variable/CMAKE_LANG_COMPILER_TARGET /variable/CMAKE_LANG_COMPILER_VERSION + /variable/CMAKE_LANG_COMPILE_OBJECT /variable/CMAKE_LANG_CREATE_SHARED_LIBRARY /variable/CMAKE_LANG_CREATE_SHARED_MODULE /variable/CMAKE_LANG_CREATE_STATIC_LIBRARY + /variable/CMAKE_LANG_FLAGS /variable/CMAKE_LANG_FLAGS_DEBUG /variable/CMAKE_LANG_FLAGS_DEBUG_INIT + /variable/CMAKE_LANG_FLAGS_INIT /variable/CMAKE_LANG_FLAGS_MINSIZEREL /variable/CMAKE_LANG_FLAGS_MINSIZEREL_INIT /variable/CMAKE_LANG_FLAGS_RELEASE /variable/CMAKE_LANG_FLAGS_RELEASE_INIT /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO /variable/CMAKE_LANG_FLAGS_RELWITHDEBINFO_INIT - /variable/CMAKE_LANG_FLAGS - /variable/CMAKE_LANG_FLAGS_INIT /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_DEBUG /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_MINSIZEREL /variable/CMAKE_LANG_GHS_KERNEL_FLAGS_RELEASE @@ -403,8 +404,8 @@ Variables for Languages /variable/CMAKE_LANG_IMPLICIT_LINK_FRAMEWORK_DIRECTORIES /variable/CMAKE_LANG_IMPLICIT_LINK_LIBRARIES /variable/CMAKE_LANG_LIBRARY_ARCHITECTURE - /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES /variable/CMAKE_LANG_LINKER_PREFERENCE + /variable/CMAKE_LANG_LINKER_PREFERENCE_PROPAGATES /variable/CMAKE_LANG_LINK_EXECUTABLE /variable/CMAKE_LANG_OUTPUT_EXTENSION /variable/CMAKE_LANG_PLATFORM_ID diff --git a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst index effa3b0..3f68c31 100644 --- a/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst +++ b/Help/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.rst @@ -5,3 +5,7 @@ Enable interprocedural optimization for a target. If set to true, enables interprocedural optimizations if they are known to be supported by the compiler. + +This property is initialized by the +:variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION` variable if it is set when a +target is created. diff --git a/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst b/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst index 4da855b..266ccf0 100644 --- a/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst +++ b/Help/prop_tgt/MAP_IMPORTED_CONFIG_CONFIG.rst @@ -23,3 +23,48 @@ is ignored for non-imported targets. This property is initialized by the value of the :variable:`CMAKE_MAP_IMPORTED_CONFIG_<CONFIG>` variable if it is set when a target is created. + +Example +^^^^^^^ + +For example creating imported C++ library ``foo``: + +.. code-block:: cmake + + add_library(foo STATIC IMPORTED) + +Use ``foo_debug`` path for ``Debug`` build type: + +.. code-block:: cmake + + set_property( + TARGET foo APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG + ) + + set_target_properties(foo PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "${foo_debug}" + ) + +Use ``foo_release`` path for ``Release`` build type: + +.. code-block:: cmake + + set_property( + TARGET foo APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE + ) + + set_target_properties(foo PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "CXX" + IMPORTED_LOCATION_RELEASE "${foo_release}" + ) + +Use ``Release`` version of library for ``MinSizeRel`` and ``RelWithDebInfo`` +build types: + +.. code-block:: cmake + + set_target_properties(foo PROPERTIES + MAP_IMPORTED_CONFIG_MINSIZEREL Release + MAP_IMPORTED_CONFIG_RELWITHDEBINFO Release + ) diff --git a/Help/release/dev/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst b/Help/release/dev/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst new file mode 100644 index 0000000..fc4f733 --- /dev/null +++ b/Help/release/dev/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst @@ -0,0 +1,6 @@ +CMAKE_INTERPROCEDURAL_OPTIMIZATION +---------------------------------- + +* A :variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION` variable was added to + initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` property on all + targets. diff --git a/Help/release/dev/cpack-sign-uninstaller.rst b/Help/release/dev/cpack-sign-uninstaller.rst new file mode 100644 index 0000000..ff2b402 --- /dev/null +++ b/Help/release/dev/cpack-sign-uninstaller.rst @@ -0,0 +1,5 @@ +cpack-sign_uninstaller +---------------------- + +* The :module:`CPackNSIS` module learned to sign the uninstaller + when using :variable:`CPACK_NSIS_SIGN_UNINSTALLER` variable. diff --git a/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst new file mode 100644 index 0000000..b0cbb62 --- /dev/null +++ b/Help/variable/CMAKE_INTERPROCEDURAL_OPTIMIZATION.rst @@ -0,0 +1,8 @@ +CMAKE_INTERPROCEDURAL_OPTIMIZATION +---------------------------------- + +Default value for :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` of targets. + +This variable is used to initialize the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` +property on all the targets. See that target property for additional +information. diff --git a/Help/variable/MSVC_VERSION.rst b/Help/variable/MSVC_VERSION.rst index e2aff3c9..8932147 100644 --- a/Help/variable/MSVC_VERSION.rst +++ b/Help/variable/MSVC_VERSION.rst @@ -13,4 +13,5 @@ Known version numbers are:: 1600 = VS 10.0 1700 = VS 11.0 1800 = VS 12.0 - 1900 = VS 14.0, 15.0 + 1900 = VS 14.0 + 1910 = VS 15.0 diff --git a/Modules/CPackNSIS.cmake b/Modules/CPackNSIS.cmake index 18d1871..37fedf3 100644 --- a/Modules/CPackNSIS.cmake +++ b/Modules/CPackNSIS.cmake @@ -133,6 +133,10 @@ # "doc/cmake-@CMake_VERSION_MAJOR@.@CMake_VERSION_MINOR@/cmake.html" # "CMake Help" "https://cmake.org" "CMake Web Site") # +# .. variable:: CPACK_NSIS_SIGN_UNINSTALLER +# +# Specify a command to use for signing the uninstaller. The command will +# be invoked a path to the uninstaller as its only argument. #FIXME we should put NSIS specific code here #FIXME but I'm not doing it because I'm not able to test it... diff --git a/Modules/CheckLanguage.cmake b/Modules/CheckLanguage.cmake index 6b4a9e4..1ea91d2 100644 --- a/Modules/CheckLanguage.cmake +++ b/Modules/CheckLanguage.cmake @@ -46,6 +46,8 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/Check${lang} COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} + -A "${CMAKE_GENERATOR_PLATFORM}" + -T "${CMAKE_GENERATOR_TOOLSET}" OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result diff --git a/Modules/FindHDF5.cmake b/Modules/FindHDF5.cmake index 927ec64..4884174 100644 --- a/Modules/FindHDF5.cmake +++ b/Modules/FindHDF5.cmake @@ -69,6 +69,9 @@ # HDF5_C_DEFINITIONS -- Required compiler definitions for HDF5 C bindings # HDF5_CXX_DEFINITIONS -- Required compiler definitions for HDF5 C++ bindings # HDF5_Fortran_DEFINITIONS -- Required compiler definitions for HDF5 Fortran bindings +# HDF5_C_INCLUDE_DIRS -- Required include directories for HDF5 C bindings +# HDF5_CXX_INCLUDE_DIRS -- Required include directories for HDF5 C++ bindings +# HDF5_Fortran_INCLUDE_DIRS -- Required include directories for HDF5 Fortran bindings # HDF5_C_LIBRARIES - Required libraries for the HDF5 C bindings # HDF5_CXX_LIBRARIES - Required libraries for the HDF5 C++ bindings # HDF5_Fortran_LIBRARIES - Required libraries for the HDF5 Fortran bindings @@ -358,7 +361,7 @@ macro( _HDF5_parse_compile_line list(APPEND ${include_paths} "${CMAKE_MATCH_1}") elseif("${arg}" MATCHES "^-D(.*)$") # compile definition - list(APPEND ${definitions} "${CMAKE_MATCH_1}") + list(APPEND ${definitions} "-D${CMAKE_MATCH_1}") elseif("${arg}" MATCHES "^-L(.*)$") # library search path list(APPEND ${library_paths} "${CMAKE_MATCH_1}") @@ -696,6 +699,8 @@ if( NOT HDF5_FOUND ) ${_HDF5_SEARCH_OPTS} ) mark_as_advanced(HDF5_${__lang}_INCLUDE_DIR) + # set the _DIRS variable as this is what the user will normally use + set(HDF5_${__lang}_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIR}) list(APPEND HDF5_INCLUDE_DIRS ${HDF5_${__lang}_INCLUDE_DIR}) # find the HDF5 libraries diff --git a/Modules/FindJNI.cmake b/Modules/FindJNI.cmake index 39e504f..cebba10 100644 --- a/Modules/FindJNI.cmake +++ b/Modules/FindJNI.cmake @@ -145,6 +145,9 @@ JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_LIBRARY_DIRECTORIES /usr/lib/jvm/default-java/jre/lib/{libarch} /usr/lib/jvm/default-java/jre/lib /usr/lib/jvm/default-java/lib + # Arch Linux specific paths for default JVM + /usr/lib/jvm/default/jre/lib/{libarch} + /usr/lib/jvm/default/lib/{libarch} # Ubuntu specific paths for default JVM /usr/lib/jvm/java-8-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 15.10 /usr/lib/jvm/java-7-openjdk-{libarch}/jre/lib/{libarch} # Ubuntu 15.10 @@ -200,6 +203,8 @@ JAVA_APPEND_LIBRARY_DIRECTORIES(JAVA_AWT_INCLUDE_DIRECTORIES /opt/sun-jdk-1.5.0.04/include # Debian specific path for default JVM /usr/lib/jvm/default-java/include + # Arch specific path for default JVM + /usr/lib/jvm/default/include # OpenBSD specific path for default JVM /usr/local/jdk-1.7.0/include /usr/local/jdk-1.6.0/include diff --git a/Modules/FindVulkan.cmake b/Modules/FindVulkan.cmake index 820e0eb..1f4c8ad 100644 --- a/Modules/FindVulkan.cmake +++ b/Modules/FindVulkan.cmake @@ -39,12 +39,17 @@ if(WIN32) find_library(Vulkan_LIBRARY NAMES vulkan-1 PATHS - "$ENV{VULKAN_SDK}/Bin") + "$ENV{VULKAN_SDK}/Lib" + "$ENV{VULKAN_SDK}/Bin" + ) elseif(CMAKE_SIZEOF_VOID_P EQUAL 4) find_library(Vulkan_LIBRARY NAMES vulkan-1 PATHS - "$ENV{VULKAN_SDK}/Bin32") + "$ENV{VULKAN_SDK}/Lib32" + "$ENV{VULKAN_SDK}/Bin32" + NO_SYSTEM_ENVIRONMENT_PATH + ) endif() else() find_path(Vulkan_INCLUDE_DIR diff --git a/Modules/NSIS.template.in b/Modules/NSIS.template.in index 9001888..ffa6277 100644 --- a/Modules/NSIS.template.in +++ b/Modules/NSIS.template.in @@ -29,6 +29,33 @@ ;-------------------------------- ;General +!ifdef INNER + OutFile "$%TEMP%\tempinstaller.exe" + SetCompress off ; for speed +!else + ; Call makensis again, defining INNER. This writes an installer for us which, when + ; it is invoked, will just write the uninstaller to some location, and then exit. + ; Be sure to substitute the name of this script here. + + !system "$\"${NSISDIR}\makensis$\" /DINNER $\"@CPACK_TEMPORARY_DIRECTORY@/../project.nsi$\"" = 0 + + ; So now run that installer we just created as %TEMP%\tempinstaller.exe. Since it + ; calls quit the return value isn't zero. + + !system "$%TEMP%\tempinstaller.exe" = 2 + + ; That will have written an uninstaller binary for us. Now we sign it with your + ; favourite code signing tool. + + !tempfile INCEXIST + !system 'if exist "@CPACK_NSIS_SIGN_UNINSTALLER@" echo !define HAVE_SIGN_UNINST > "${INCEXIST}"' + !include "${INCEXIST}" + !delfile "${INCEXIST}" + !ifdef HAVE_SIGN_UNINST + !system '"@CPACK_NSIS_SIGN_UNINSTALLER@" "$%TEMP%\Uninstall.exe"' = 0 + !endif + + ; Good. Now we can carry on writing the real installer. ;Name and file Name "@CPACK_NSIS_PACKAGE_NAME@" @@ -36,6 +63,7 @@ ;Set compression SetCompressor @CPACK_NSIS_COMPRESSOR@ +!endif ;Require administrator access RequestExecutionLevel admin @@ -559,8 +587,10 @@ FunctionEnd !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_PAGE_FINISH +!ifdef INNER !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES +!endif ;-------------------------------- ;Languages @@ -642,7 +672,10 @@ Section "-Core installation" WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR ;Create uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" +!ifndef INNER + ; this packages the signed uninstaller + File "$%TEMP%\Uninstall.exe" +!endif Push "DisplayName" Push "@CPACK_NSIS_DISPLAY_NAME@" Call ConditionalAddToRegisty @@ -801,6 +834,7 @@ FunctionEnd ;-------------------------------- ;Uninstaller Section +!ifdef INNER Section "Uninstall" ReadRegStr $START_MENU SHCTX \ "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "StartMenu" @@ -886,6 +920,7 @@ Section "Uninstall" Call un.RemoveFromPath doNotRemoveFromPath: SectionEnd +!endif ;-------------------------------- ; determine admin versus local install @@ -898,6 +933,14 @@ SectionEnd ; "Program Files" for AllUsers, "My Documents" for JustMe... Function .onInit +!ifdef INNER + ; If INNER is defined, then we aren't supposed to do anything except write out + ; the installer. This is better than processing a command line option as it means + ; this entire code path is not present in the final (real) installer. + + WriteUninstaller "$%TEMP%\Uninstall.exe" + Quit ; just bail out quickly when running the "inner" installer +!endif StrCmp "@CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL@" "ON" 0 inst ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "UninstallString" diff --git a/Modules/WriteCompilerDetectionHeader.cmake b/Modules/WriteCompilerDetectionHeader.cmake index 0b16aa4..362099e 100644 --- a/Modules/WriteCompilerDetectionHeader.cmake +++ b/Modules/WriteCompilerDetectionHeader.cmake @@ -503,10 +503,19 @@ function(write_compiler_detection_header if (feature STREQUAL cxx_static_assert) set(def_value "${prefix_arg}_STATIC_ASSERT(X)") set(def_value_msg "${prefix_arg}_STATIC_ASSERT_MSG(X, MSG)") - set(static_assert_struct "template<bool> struct ${prefix_arg}StaticAssert;\ntemplate<> struct ${prefix_arg}StaticAssert<true>{};\n") - set(def_standard "# define ${def_value} static_assert(X, #X)\n# define ${def_value_msg} static_assert(X, MSG)") - set(def_alternative "${static_assert_struct}# define ${def_value} sizeof(${prefix_arg}StaticAssert<X>)\n# define ${def_value_msg} sizeof(${prefix_arg}StaticAssert<X>)") - string(APPEND file_content "# if defined(${def_name}) && ${def_name}\n${def_standard}\n# else\n${def_alternative}\n# endif\n\n") + set(def_fallback "enum { ${prefix_arg}_STATIC_ASSERT_JOIN(${prefix_arg}StaticAssertEnum, __LINE__) = sizeof(${prefix_arg}StaticAssert<X>) }") + string(APPEND file_content "# if defined(${def_name}) && ${def_name} +# define ${def_value} static_assert(X, #X) +# define ${def_value_msg} static_assert(X, MSG) +# else +# define ${prefix_arg}_STATIC_ASSERT_JOIN(X, Y) ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y) +# define ${prefix_arg}_STATIC_ASSERT_JOIN_IMPL(X, Y) X##Y +template<bool> struct ${prefix_arg}StaticAssert; +template<> struct ${prefix_arg}StaticAssert<true>{}; +# define ${def_value} ${def_fallback} +# define ${def_value_msg} ${def_fallback} +# endif +\n") endif() if (feature STREQUAL cxx_alignas) set(def_value "${prefix_arg}_ALIGNAS(X)") diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 76b98fc..59920f8 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -344,6 +344,8 @@ set(SRCS cmPropertyDefinitionMap.h cmPropertyMap.cxx cmPropertyMap.h + cmQtAutoGeneratorCommon.cxx + cmQtAutoGeneratorCommon.h cmQtAutoGeneratorInitializer.cxx cmQtAutoGeneratorInitializer.h cmQtAutoGenerators.cxx @@ -381,6 +383,8 @@ set(SRCS cmVariableWatch.h cmVersion.cxx cmVersion.h + cmWorkingDirectory.cxx + cmWorkingDirectory.h cmXMLParser.cxx cmXMLParser.h cmXMLSafe.cxx diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 62324e8..6efbf47 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 8) -set(CMake_VERSION_PATCH 20170302) +set(CMake_VERSION_PATCH 20170309) #set(CMake_VERSION_RC 1) diff --git a/Source/CPack/OSXScriptLauncher.cxx b/Source/CPack/OSXScriptLauncher.cxx index b159e64..aeabde9 100644 --- a/Source/CPack/OSXScriptLauncher.cxx +++ b/Source/CPack/OSXScriptLauncher.cxx @@ -20,7 +20,6 @@ int main(int argc, char* argv[]) { // if ( cmsys::SystemTools::FileExists( - std::string cwd = cmsys::SystemTools::GetCurrentWorkingDirectory(); cmsys::ofstream ofs("/tmp/output.txt"); CFStringRef fileName; diff --git a/Source/CPack/cmCPackArchiveGenerator.cxx b/Source/CPack/cmCPackArchiveGenerator.cxx index 9d9cd66..cc01b0c 100644 --- a/Source/CPack/cmCPackArchiveGenerator.cxx +++ b/Source/CPack/cmCPackArchiveGenerator.cxx @@ -7,6 +7,7 @@ #include "cmCPackLog.h" #include "cmGeneratedFileStream.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include <map> #include <ostream> @@ -37,9 +38,8 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( // Add the files of this component to the archive std::string localToplevel(this->GetOption("CPACK_TEMPORARY_DIRECTORY")); localToplevel += "/" + component->Name; - std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); // Change to local toplevel - cmSystemTools::ChangeDirectory(localToplevel); + cmWorkingDirectory workdir(localToplevel); std::string filePrefix; if (this->IsOn("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")) { filePrefix = this->GetOption("CPACK_PACKAGE_FILE_NAME"); @@ -64,8 +64,6 @@ int cmCPackArchiveGenerator::addOneComponentToArchive( return 0; } } - // Go back to previous dir - cmSystemTools::ChangeDirectory(dir); return 1; } @@ -227,8 +225,7 @@ int cmCPackArchiveGenerator::PackageFiles() // CASE 3 : NON COMPONENT package. DECLARE_AND_OPEN_ARCHIVE(packageFileNames[0], archive); std::vector<std::string>::const_iterator fileIt; - std::string dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(toplevel); + cmWorkingDirectory workdir(toplevel); for (fileIt = files.begin(); fileIt != files.end(); ++fileIt) { // Get the relative path to the file std::string rp = @@ -241,7 +238,6 @@ int cmCPackArchiveGenerator::PackageFiles() return 0; } } - cmSystemTools::ChangeDirectory(dir); // The destructor of cmArchiveWrite will close and finish the write return 1; } diff --git a/Source/CPack/cmCPackGenerator.cxx b/Source/CPack/cmCPackGenerator.cxx index e1a4a2a..f6ea8cf 100644 --- a/Source/CPack/cmCPackGenerator.cxx +++ b/Source/CPack/cmCPackGenerator.cxx @@ -16,6 +16,7 @@ #include "cmGlobalGenerator.h" #include "cmMakefile.h" #include "cmStateSnapshot.h" +#include "cmWorkingDirectory.h" #include "cmXMLSafe.h" #include "cm_auto_ptr.hxx" #include "cmake.h" @@ -383,7 +384,7 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( goToDir += "/" + subdir; cmCPackLogger(cmCPackLog::LOG_DEBUG, "Change dir to: " << goToDir << std::endl); - cmSystemTools::ChangeDirectory(goToDir); + cmWorkingDirectory workdir(goToDir); for (symlinkedIt = symlinkedFiles.begin(); symlinkedIt != symlinkedFiles.end(); ++symlinkedIt) { cmCPackLogger(cmCPackLog::LOG_DEBUG, "Will create a symlink: " @@ -408,7 +409,6 @@ int cmCPackGenerator::InstallProjectViaInstalledDirectories( } cmCPackLogger(cmCPackLog::LOG_DEBUG, "Going back to: " << curDir << std::endl); - cmSystemTools::ChangeDirectory(curDir); } } } diff --git a/Source/CTest/cmCTestBuildAndTestHandler.cxx b/Source/CTest/cmCTestBuildAndTestHandler.cxx index 6780a0e..6f81429 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.cxx +++ b/Source/CTest/cmCTestBuildAndTestHandler.cxx @@ -6,6 +6,7 @@ #include "cmCTestTestHandler.h" #include "cmGlobalGenerator.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include "cmake.h" #include <cmsys/Process.h> @@ -42,7 +43,7 @@ int cmCTestBuildAndTestHandler::ProcessHandler() int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, std::ostringstream& out, std::string& cmakeOutString, - std::string& cwd, cmake* cm) + cmake* cm) { unsigned int k; std::vector<std::string> args; @@ -85,8 +86,6 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, if (cm->Run(args) != 0) { out << "Error: cmake execution failed\n"; out << cmakeOutString << "\n"; - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); if (outstring) { *outstring = out.str(); } else { @@ -99,8 +98,6 @@ int cmCTestBuildAndTestHandler::RunCMake(std::string* outstring, if (cm->Run(args) != 0) { out << "Error: cmake execution failed\n"; out << cmakeOutString << "\n"; - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); if (outstring) { *outstring = out.str(); } else { @@ -199,13 +196,12 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) double clock_start = cmSystemTools::GetTime(); // make sure the binary dir is there - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); out << "Internal cmake changing into directory: " << this->BinaryDir << std::endl; if (!cmSystemTools::FileIsDirectory(this->BinaryDir)) { cmSystemTools::MakeDirectory(this->BinaryDir.c_str()); } - cmSystemTools::ChangeDirectory(this->BinaryDir); + cmWorkingDirectory workdir(this->BinaryDir); if (this->BuildNoCMake) { // Make the generator available for the Build call below. @@ -217,7 +213,7 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) cm.LoadCache(this->BinaryDir); } else { // do the cmake step, no timeout here since it is not a sub process - if (this->RunCMake(outstring, out, cmakeOutString, cwd, &cm)) { + if (this->RunCMake(outstring, out, cmakeOutString, &cm)) { return 1; } } @@ -304,8 +300,6 @@ int cmCTestBuildAndTestHandler::RunCMakeAndTest(std::string* outstring) } else { cmCTestLog(this->CTest, ERROR_MESSAGE, out.str()); } - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); return 1; } diff --git a/Source/CTest/cmCTestBuildAndTestHandler.h b/Source/CTest/cmCTestBuildAndTestHandler.h index 5885738..af082a3 100644 --- a/Source/CTest/cmCTestBuildAndTestHandler.h +++ b/Source/CTest/cmCTestBuildAndTestHandler.h @@ -46,7 +46,7 @@ protected: ///! Run CMake and build a test and then run it as a single test. int RunCMakeAndTest(std::string* output); int RunCMake(std::string* outstring, std::ostringstream& out, - std::string& cmakeOutString, std::string& cwd, cmake* cm); + std::string& cmakeOutString, cmake* cm); std::string Output; diff --git a/Source/CTest/cmCTestCoverageHandler.cxx b/Source/CTest/cmCTestCoverageHandler.cxx index 989c096..120c5d9 100644 --- a/Source/CTest/cmCTestCoverageHandler.cxx +++ b/Source/CTest/cmCTestCoverageHandler.cxx @@ -12,6 +12,7 @@ #include "cmParseJacocoCoverage.h" #include "cmParsePHPCoverage.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include "cmXMLWriter.h" #include "cmake.h" @@ -969,9 +970,8 @@ int cmCTestCoverageHandler::HandleGCovCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory(); cmSystemTools::MakeDirectory(tempDir.c_str()); - cmSystemTools::ChangeDirectory(tempDir); + cmWorkingDirectory workdir(tempDir); int gcovStyle = 0; @@ -1294,7 +1294,6 @@ int cmCTestCoverageHandler::HandleGCovCoverage( } } - cmSystemTools::ChangeDirectory(currentDirectory); return file_count; } @@ -1340,7 +1339,6 @@ int cmCTestCoverageHandler::HandleLCovCoverage( return 0; } std::string testingDir = this->CTest->GetBinaryDir(); - std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory(); std::set<std::string> missingFiles; @@ -1362,7 +1360,7 @@ int cmCTestCoverageHandler::HandleLCovCoverage( cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, "." << std::flush, this->Quiet); std::string fileDir = cmSystemTools::GetFilenamePath(*it); - cmSystemTools::ChangeDirectory(fileDir); + cmWorkingDirectory workdir(fileDir); std::string command = "\"" + lcovCommand + "\" " + lcovExtraFlags + " "; cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, @@ -1552,7 +1550,6 @@ int cmCTestCoverageHandler::HandleLCovCoverage( } } - cmSystemTools::ChangeDirectory(currentDirectory); return file_count; } @@ -1591,13 +1588,8 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) gl.RecurseOff(); // No need of recurse if -prof_dir${BUILD_DIR} flag is // used while compiling. gl.RecurseThroughSymlinksOff(); - std::string prevBinaryDir; std::string buildDir = this->CTest->GetCTestConfiguration("BuildDirectory"); - if (cmSystemTools::ChangeDirectory(buildDir)) { - cmCTestLog(this->CTest, ERROR_MESSAGE, "Error changing directory to " - << buildDir << std::endl); - return false; - } + cmWorkingDirectory workdir(buildDir); // Run profmerge to merge all *.dyn files into dpi files if (!cmSystemTools::RunSingleCommand("profmerge")) { @@ -1605,11 +1597,9 @@ bool cmCTestCoverageHandler::FindLCovFiles(std::vector<std::string>& files) return false; } - prevBinaryDir = cmSystemTools::GetCurrentWorkingDirectory(); - // DPI file should appear in build directory std::string daGlob; - daGlob = prevBinaryDir; + daGlob = buildDir; daGlob += "/*.dpi"; cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " looking for dpi files in: " << daGlob << std::endl, @@ -1646,11 +1636,7 @@ int cmCTestCoverageHandler::HandleTracePyCoverage( std::string testingDir = this->CTest->GetBinaryDir() + "/Testing"; std::string tempDir = testingDir + "/CoverageInfo"; - std::string currentDirectory = cmSystemTools::GetCurrentWorkingDirectory(); cmSystemTools::MakeDirectory(tempDir.c_str()); - cmSystemTools::ChangeDirectory(tempDir); - - cmSystemTools::ChangeDirectory(currentDirectory); std::vector<std::string>::iterator fileIt; int file_count = 0; @@ -1737,7 +1723,6 @@ int cmCTestCoverageHandler::HandleTracePyCoverage( } ++file_count; } - cmSystemTools::ChangeDirectory(currentDirectory); return file_count; } diff --git a/Source/CTest/cmCTestHandlerCommand.cxx b/Source/CTest/cmCTestHandlerCommand.cxx index 2a67d47..c99e450 100644 --- a/Source/CTest/cmCTestHandlerCommand.cxx +++ b/Source/CTest/cmCTestHandlerCommand.cxx @@ -6,6 +6,7 @@ #include "cmCTestGenericHandler.h" #include "cmMakefile.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include "cmake.h" #include <sstream> @@ -216,8 +217,7 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, handler->SetSubmitIndex(atoi(this->Values[ct_SUBMIT_INDEX])); } } - std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory( + cmWorkingDirectory workdir( this->CTest->GetCTestConfiguration("BuildDirectory")); int res = handler->ProcessHandler(); if (this->Values[ct_RETURN_VALUE] && *this->Values[ct_RETURN_VALUE]) { @@ -243,7 +243,6 @@ bool cmCTestHandlerCommand::InitialPass(std::vector<std::string> const& args, this->Makefile->AddDefinition(this->Values[ct_CAPTURE_CMAKE_ERROR], returnString); } - cmSystemTools::ChangeDirectory(current_dir); return true; } diff --git a/Source/CTest/cmCTestMultiProcessHandler.cxx b/Source/CTest/cmCTestMultiProcessHandler.cxx index c1724ab..ff465ab 100644 --- a/Source/CTest/cmCTestMultiProcessHandler.cxx +++ b/Source/CTest/cmCTestMultiProcessHandler.cxx @@ -7,6 +7,7 @@ #include "cmCTestScriptHandler.h" #include "cmCTestTestHandler.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include <algorithm> #include <cmsys/FStream.hxx> @@ -138,8 +139,7 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) } } - std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(this->Properties[test]->Directory); + cmWorkingDirectory workdir(this->Properties[test]->Directory); // Lock the resources we'll be using this->LockResources(test); @@ -166,7 +166,6 @@ void cmCTestMultiProcessHandler::StartTestProcess(int test) this->Failed->push_back(this->Properties[test]->Name); delete testRun; } - cmSystemTools::ChangeDirectory(current_dir); } void cmCTestMultiProcessHandler::LockResources(int index) @@ -683,9 +682,7 @@ void cmCTestMultiProcessHandler::PrintTestList() count++; cmCTestTestHandler::cmCTestTestProperties& p = *it->second; - // push working dir - std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(p.Directory); + cmWorkingDirectory workdir(p.Directory); cmCTestRunTest testRun(this->TestHandler); testRun.SetIndex(p.Index); @@ -724,8 +721,6 @@ void cmCTestMultiProcessHandler::PrintTestList() cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " ", this->Quiet); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, p.Name << std::endl, this->Quiet); - // pop working dir - cmSystemTools::ChangeDirectory(current_dir); } cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, std::endl diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index ac1644f..f148f30 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -7,6 +7,7 @@ #include "cmCTestTestHandler.h" #include "cmProcess.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include <cmConfigure.h> #include <cm_curl.h> @@ -270,14 +271,11 @@ bool cmCTestRunTest::EndTest(size_t completed, size_t total, bool started) *this->TestHandler->LogFile << "Test time = " << buf << std::endl; } - // Set the working directory to the tests directory - std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(this->TestProperties->Directory); - - this->DartProcessing(); - - // restore working directory - cmSystemTools::ChangeDirectory(oldpath); + // Set the working directory to the tests directory to process Dart files. + { + cmWorkingDirectory workdir(this->TestProperties->Directory); + this->DartProcessing(); + } // if this is doing MemCheck then all the output needs to be put into // Output since that is what is parsed by cmCTestMemCheckHandler @@ -356,11 +354,8 @@ bool cmCTestRunTest::StartAgain() } this->RunAgain = false; // reset // change to tests directory - std::string current_dir = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(this->TestProperties->Directory); + cmWorkingDirectory workdir(this->TestProperties->Directory); this->StartTest(this->TotalNumberOfTests); - // change back - cmSystemTools::ChangeDirectory(current_dir); return true; } diff --git a/Source/CTest/cmCTestSubmitHandler.cxx b/Source/CTest/cmCTestSubmitHandler.cxx index 5e5119d..cc399b0 100644 --- a/Source/CTest/cmCTestSubmitHandler.cxx +++ b/Source/CTest/cmCTestSubmitHandler.cxx @@ -19,6 +19,7 @@ #include "cmState.h" #include "cmSystemTools.h" #include "cmThirdParty.h" +#include "cmWorkingDirectory.h" #include "cmXMLParser.h" #include "cmake.h" @@ -1519,7 +1520,6 @@ int cmCTestSubmitHandler::ProcessHandler() #endif } else if (dropMethod == "scp") { std::string url; - std::string oldWorkingDirectory; if (!this->CTest->GetCTestConfiguration("DropSiteUser").empty()) { url += this->CTest->GetCTestConfiguration("DropSiteUser") + "@"; } @@ -1528,19 +1528,16 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp dosn't support "c:" a drive in the path - oldWorkingDirectory = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(buildDirectory); + cmWorkingDirectory workdir(buildDirectory); if (!this->SubmitUsingSCP(this->CTest->GetCTestConfiguration("ScpCommand"), "Testing/" + this->CTest->GetCurrentTag(), files, prefix, url)) { - cmSystemTools::ChangeDirectory(oldWorkingDirectory); cmCTestLog(this->CTest, ERROR_MESSAGE, " Problems when submitting via SCP" << std::endl); ofs << " Problems when submitting via SCP" << std::endl; return -1; } - cmSystemTools::ChangeDirectory(oldWorkingDirectory); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Submission successful" << std::endl, this->Quiet); ofs << " Submission successful" << std::endl; @@ -1550,22 +1547,18 @@ int cmCTestSubmitHandler::ProcessHandler() // change to the build directory so that we can uses a relative path // on windows since scp dosn't support "c:" a drive in the path - std::string oldWorkingDirectory = - cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(buildDirectory); + cmWorkingDirectory workdir(buildDirectory); cmCTestOptionalLog(this->CTest, HANDLER_VERBOSE_OUTPUT, " Change directory: " << buildDirectory << std::endl, this->Quiet); if (!this->SubmitUsingCP("Testing/" + this->CTest->GetCurrentTag(), files, prefix, location)) { - cmSystemTools::ChangeDirectory(oldWorkingDirectory); cmCTestLog(this->CTest, ERROR_MESSAGE, " Problems when submitting via CP" << std::endl); ofs << " Problems when submitting via cp" << std::endl; return -1; } - cmSystemTools::ChangeDirectory(oldWorkingDirectory); cmCTestOptionalLog(this->CTest, HANDLER_OUTPUT, " Submission successful" << std::endl, this->Quiet); ofs << " Submission successful" << std::endl; diff --git a/Source/CTest/cmCTestTestHandler.cxx b/Source/CTest/cmCTestTestHandler.cxx index 6175e50..9d22065 100644 --- a/Source/CTest/cmCTestTestHandler.cxx +++ b/Source/CTest/cmCTestTestHandler.cxx @@ -27,6 +27,7 @@ #include "cmState.h" #include "cmStateSnapshot.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include "cmXMLWriter.h" #include "cm_auto_ptr.hxx" #include "cm_utf8.h" @@ -86,22 +87,24 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, // No subdirectory? So what... continue; } - cmSystemTools::ChangeDirectory(fname); - const char* testFilename; - if (cmSystemTools::FileExists("CTestTestfile.cmake")) { - // does the CTestTestfile.cmake exist ? - testFilename = "CTestTestfile.cmake"; - } else if (cmSystemTools::FileExists("DartTestfile.txt")) { - // does the DartTestfile.txt exist ? - testFilename = "DartTestfile.txt"; - } else { - // No CTestTestfile? Who cares... - continue; + bool readit = false; + { + cmWorkingDirectory workdir(fname); + const char* testFilename; + if (cmSystemTools::FileExists("CTestTestfile.cmake")) { + // does the CTestTestfile.cmake exist ? + testFilename = "CTestTestfile.cmake"; + } else if (cmSystemTools::FileExists("DartTestfile.txt")) { + // does the DartTestfile.txt exist ? + testFilename = "DartTestfile.txt"; + } else { + // No CTestTestfile? Who cares... + continue; + } + fname += "/"; + fname += testFilename; + readit = this->Makefile->ReadDependentFile(fname.c_str()); } - fname += "/"; - fname += testFilename; - bool readit = this->Makefile->ReadDependentFile(fname.c_str()); - cmSystemTools::ChangeDirectory(cwd); if (!readit) { std::string m = "Could not find include file: "; m += fname; @@ -109,7 +112,6 @@ bool cmCTestSubdirCommand::InitialPass(std::vector<std::string> const& args, return false; } } - cmSystemTools::ChangeDirectory(cwd); return true; } @@ -149,9 +151,7 @@ bool cmCTestAddSubdirectoryCommand::InitialPass( return false; } - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(cwd); - std::string fname = cwd; + std::string fname = cmSystemTools::GetCurrentWorkingDirectory(); fname += "/"; fname += args[0]; @@ -159,23 +159,23 @@ bool cmCTestAddSubdirectoryCommand::InitialPass( // No subdirectory? So what... return true; } - cmSystemTools::ChangeDirectory(fname); - const char* testFilename; - if (cmSystemTools::FileExists("CTestTestfile.cmake")) { - // does the CTestTestfile.cmake exist ? - testFilename = "CTestTestfile.cmake"; - } else if (cmSystemTools::FileExists("DartTestfile.txt")) { - // does the DartTestfile.txt exist ? - testFilename = "DartTestfile.txt"; - } else { - // No CTestTestfile? Who cares... - cmSystemTools::ChangeDirectory(cwd); - return true; + bool readit = false; + { + const char* testFilename; + if (cmSystemTools::FileExists("CTestTestfile.cmake")) { + // does the CTestTestfile.cmake exist ? + testFilename = "CTestTestfile.cmake"; + } else if (cmSystemTools::FileExists("DartTestfile.txt")) { + // does the DartTestfile.txt exist ? + testFilename = "DartTestfile.txt"; + } else { + // No CTestTestfile? Who cares... + return true; + } + fname += "/"; + fname += testFilename; + readit = this->Makefile->ReadDependentFile(fname.c_str()); } - fname += "/"; - fname += testFilename; - bool readit = this->Makefile->ReadDependentFile(fname.c_str()); - cmSystemTools::ChangeDirectory(cwd); if (!readit) { std::string m = "Could not find include file: "; m += fname; diff --git a/Source/cmCTest.cxx b/Source/cmCTest.cxx index 559275e..e6e50e9 100644 --- a/Source/cmCTest.cxx +++ b/Source/cmCTest.cxx @@ -1122,7 +1122,6 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, if (log) { *log << "* Run internal CTest" << std::endl; } - std::string oldpath = cmSystemTools::GetCurrentWorkingDirectory(); CM_AUTO_PTR<cmSystemTools::SaveRestoreEnvironment> saveEnv; if (modifyEnv) { @@ -1137,7 +1136,6 @@ int cmCTest::RunTest(std::vector<const char*> argv, std::string* output, if (log && output) { *log << *output; } - cmSystemTools::ChangeDirectory(oldpath); if (output) { cmCTestLog(this, HANDLER_VERBOSE_OUTPUT, "Internal cmCTest object used to run test." << std::endl diff --git a/Source/cmDepends.cxx b/Source/cmDepends.cxx index c189419..b8c76b9 100644 --- a/Source/cmDepends.cxx +++ b/Source/cmDepends.cxx @@ -7,6 +7,7 @@ #include "cmLocalGenerator.h" #include "cmMakefile.h" #include "cmSystemTools.h" +#include "cmWorkingDirectory.h" #include <cmsys/FStream.hxx> #include <sstream> @@ -75,13 +76,7 @@ bool cmDepends::Check(const char* makeFile, const char* internalFile, std::map<std::string, DependencyVector>& validDeps) { // Dependency checks must be done in proper working directory. - std::string oldcwd = "."; - if (this->CompileDirectory != ".") { - // Get the CWD but do not call CollapseFullPath because - // we only need it to cd back, and the form does not matter - oldcwd = cmSystemTools::GetCurrentWorkingDirectory(false); - cmSystemTools::ChangeDirectory(this->CompileDirectory); - } + cmWorkingDirectory workdir(this->CompileDirectory); // Check whether dependencies must be regenerated. bool okay = true; @@ -93,11 +88,6 @@ bool cmDepends::Check(const char* makeFile, const char* internalFile, okay = false; } - // Restore working directory. - if (oldcwd != ".") { - cmSystemTools::ChangeDirectory(oldcwd); - } - return okay; } diff --git a/Source/cmFileMonitor.h b/Source/cmFileMonitor.h index 48169b8..2957328 100644 --- a/Source/cmFileMonitor.h +++ b/Source/cmFileMonitor.h @@ -2,6 +2,8 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #pragma once +#include <cmConfigure.h> // IWYU pragma: keep + #include <functional> #include <string> #include <vector> diff --git a/Source/cmGlobalGenerator.cxx b/Source/cmGlobalGenerator.cxx index b6b7d9e..1f5e624 100644 --- a/Source/cmGlobalGenerator.cxx +++ b/Source/cmGlobalGenerator.cxx @@ -42,6 +42,7 @@ #include "cmStateDirectory.h" #include "cmStateTypes.h" #include "cmVersion.h" +#include "cmWorkingDirectory.h" #include "cmake.h" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -1763,8 +1764,7 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, /** * Run an executable command and put the stdout in output. */ - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(bindir); + cmWorkingDirectory workdir(bindir); output += "Change Dir: "; output += bindir; output += "\n"; @@ -1804,8 +1804,6 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, output += *outputPtr; output += "\nGenerator: execution of make clean failed.\n"; - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); return 1; } output += *outputPtr; @@ -1828,8 +1826,6 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, output += "\nGenerator: execution of make failed. Make command was: " + makeCommandStr + "\n"; - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); return 1; } output += *outputPtr; @@ -1842,7 +1838,6 @@ int cmGlobalGenerator::Build(const std::string& /*unused*/, retVal = 1; } - cmSystemTools::ChangeDirectory(cwd); return retVal; } diff --git a/Source/cmGlobalVisualStudioGenerator.cxx b/Source/cmGlobalVisualStudioGenerator.cxx index cc2536c..ced0c26 100644 --- a/Source/cmGlobalVisualStudioGenerator.cxx +++ b/Source/cmGlobalVisualStudioGenerator.cxx @@ -750,6 +750,10 @@ bool cmGlobalVisualStudioGenerator::TargetIsCSharpOnly( if (!gt->GetConfigCommonSourceFiles(sources)) { return false; } + // Only "real" targets are allowed to be C# targets. + if (gt->Target->GetType() > cmStateEnums::OBJECT_LIBRARY) { + return false; + } } gt->GetLanguages(languages, ""); if (languages.size() == 1) { diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 07d712c..82bf0b9 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -213,14 +213,7 @@ void cmLocalGenerator::TraceDependencies() void cmLocalGenerator::GenerateTestFiles() { - std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary(); - file += "/"; - file += "CTestTestfile.cmake"; - if (!this->Makefile->IsOn("CMAKE_TESTING_ENABLED")) { - if (cmSystemTools::FileExists(file)) { - cmSystemTools::RemoveFile(file); - } return; } @@ -229,6 +222,10 @@ void cmLocalGenerator::GenerateTestFiles() const std::string& config = this->Makefile->GetConfigurations(configurationTypes, false); + std::string file = this->StateSnapshot.GetDirectory().GetCurrentBinary(); + file += "/"; + file += "CTestTestfile.cmake"; + cmGeneratedFileStream fout(file.c_str()); fout.SetCopyIfDifferent(true); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index da32dd7..c4a488f 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -36,6 +36,7 @@ #include "cmTest.h" #include "cmTestGenerator.h" // IWYU pragma: keep #include "cmVersion.h" +#include "cmWorkingDirectory.h" #include "cm_auto_ptr.hxx" #include "cmake.h" @@ -3164,8 +3165,7 @@ int cmMakefile::TryCompile(const std::string& srcdir, // change to the tests directory and run cmake // use the cmake object instead of calling cmake - std::string cwd = cmSystemTools::GetCurrentWorkingDirectory(); - cmSystemTools::ChangeDirectory(bindir); + cmWorkingDirectory workdir(bindir); // make sure the same generator is used // use this program as the cmake to be run, it should not @@ -3179,8 +3179,6 @@ int cmMakefile::TryCompile(const std::string& srcdir, this->GetGlobalGenerator()->GetName() + "' could not be created."); cmSystemTools::SetFatalErrorOccured(); - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; return 1; } @@ -3244,8 +3242,6 @@ int cmMakefile::TryCompile(const std::string& srcdir, this->IssueMessage(cmake::FATAL_ERROR, "Failed to configure test project build system."); cmSystemTools::SetFatalErrorOccured(); - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; return 1; } @@ -3254,8 +3250,6 @@ int cmMakefile::TryCompile(const std::string& srcdir, this->IssueMessage(cmake::FATAL_ERROR, "Failed to generate test project build system."); cmSystemTools::SetFatalErrorOccured(); - // return to the original directory - cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; return 1; } @@ -3264,7 +3258,6 @@ int cmMakefile::TryCompile(const std::string& srcdir, int ret = this->GetGlobalGenerator()->TryCompile( srcdir, bindir, projectName, targetName, fast, output, this); - cmSystemTools::ChangeDirectory(cwd); this->IsSourceFileTryCompile = false; return ret; } diff --git a/Source/cmOrderDirectories.cxx b/Source/cmOrderDirectories.cxx index 7744a5a..d48eb53 100644 --- a/Source/cmOrderDirectories.cxx +++ b/Source/cmOrderDirectories.cxx @@ -287,8 +287,7 @@ void cmOrderDirectories::AddRuntimeLibrary(std::string const& fullPath, } } - if (this->ImplicitDirectories.find(dir) != - this->ImplicitDirectories.end()) { + if (this->IsImplicitDirectory(dir)) { this->ImplicitDirEntries.push_back( new cmOrderDirectoriesConstraintSOName(this, fullPath, soname)); return; @@ -316,8 +315,7 @@ void cmOrderDirectories::AddLinkLibrary(std::string const& fullPath) // Implicit link directories need special handling. if (!this->ImplicitDirectories.empty()) { std::string dir = cmSystemTools::GetFilenamePath(fullPath); - if (this->ImplicitDirectories.find(dir) != - this->ImplicitDirectories.end()) { + if (this->IsImplicitDirectory(dir)) { this->ImplicitDirEntries.push_back( new cmOrderDirectoriesConstraintLibrary(this, fullPath)); return; @@ -347,7 +345,18 @@ void cmOrderDirectories::AddLanguageDirectories( void cmOrderDirectories::SetImplicitDirectories( std::set<std::string> const& implicitDirs) { - this->ImplicitDirectories = implicitDirs; + this->ImplicitDirectories.clear(); + for (std::set<std::string>::const_iterator i = implicitDirs.begin(); + i != implicitDirs.end(); ++i) { + this->ImplicitDirectories.insert(this->GetRealPath(*i)); + } +} + +bool cmOrderDirectories::IsImplicitDirectory(std::string const& dir) +{ + std::string const& real = this->GetRealPath(dir); + return this->ImplicitDirectories.find(real) != + this->ImplicitDirectories.end(); } void cmOrderDirectories::SetLinkExtensionInfo( @@ -394,8 +403,7 @@ void cmOrderDirectories::AddOriginalDirectories( for (std::vector<std::string>::const_iterator di = dirs.begin(); di != dirs.end(); ++di) { // We never explicitly specify implicit link directories. - if (this->ImplicitDirectories.find(*di) != - this->ImplicitDirectories.end()) { + if (this->IsImplicitDirectory(*di)) { continue; } diff --git a/Source/cmOrderDirectories.h b/Source/cmOrderDirectories.h index 90a67e7..d9e0126 100644 --- a/Source/cmOrderDirectories.h +++ b/Source/cmOrderDirectories.h @@ -82,6 +82,8 @@ private: // Compare directories after resolving symlinks. bool IsSameDirectory(std::string const& l, std::string const& r); + bool IsImplicitDirectory(std::string const& dir); + std::string const& GetRealPath(std::string const& dir); std::map<std::string, std::string> RealPaths; diff --git a/Source/cmQtAutoGeneratorCommon.cxx b/Source/cmQtAutoGeneratorCommon.cxx new file mode 100644 index 0000000..dcd61a3 --- /dev/null +++ b/Source/cmQtAutoGeneratorCommon.cxx @@ -0,0 +1,215 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmQtAutoGeneratorCommon.h" +#include "cmAlgorithms.h" +#include "cmSystemTools.h" + +#include <cmsys/FStream.hxx> +#include <cmsys/RegularExpression.hxx> + +#include <sstream> + +// - Static functions + +static std::string utilStripCR(std::string const& line) +{ + // Strip CR characters rcc may have printed (possibly more than one!). + std::string::size_type cr = line.find('\r'); + if (cr != line.npos) { + return line.substr(0, cr); + } + return line; +} + +/// @brief Reads the resource files list from from a .qrc file - Qt4 version +/// @return True if the .qrc file was successfully parsed +static bool RccListInputsQt4(const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + bool allGood = true; + // Read qrc file content into string + std::string qrcContents; + { + cmsys::ifstream ifs(fileName.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + qrcContents = osst.str(); + } else { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc file not readable:\n" + << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + *errorMessage = ost.str(); + } + allGood = false; + } + } + if (allGood) { + // qrc file directory + std::string qrcDir(cmsys::SystemTools::GetFilenamePath(fileName)); + if (!qrcDir.empty()) { + qrcDir += '/'; + } + + cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); + cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); + + size_t offset = 0; + while (fileMatchRegex.find(qrcContents.c_str() + offset)) { + std::string qrcEntry = fileMatchRegex.match(1); + offset += qrcEntry.size(); + { + fileReplaceRegex.find(qrcEntry); + std::string tag = fileReplaceRegex.match(1); + qrcEntry = qrcEntry.substr(tag.size()); + } + if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { + qrcEntry = qrcDir + qrcEntry; + } + files.push_back(qrcEntry); + } + } + return allGood; +} + +/// @brief Reads the resource files list from from a .qrc file - Qt5 version +/// @return True if the .qrc file was successfully parsed +static bool RccListInputsQt5(const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + if (rccCommand.empty()) { + cmSystemTools::Error("AutoRcc: Error: rcc executable not available\n"); + return false; + } + + // Read rcc features + bool hasDashDashList = false; + { + std::vector<std::string> command; + command.push_back(rccCommand); + command.push_back("--help"); + std::string rccStdOut; + std::string rccStdErr; + int retVal = 0; + bool result = + cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, + CM_NULLPTR, cmSystemTools::OUTPUT_NONE); + if (result && retVal == 0 && + rccStdOut.find("--list") != std::string::npos) { + hasDashDashList = true; + } + } + + // Run rcc list command + bool result = false; + int retVal = 0; + std::string rccStdOut; + std::string rccStdErr; + { + std::vector<std::string> command; + command.push_back(rccCommand); + command.push_back(hasDashDashList ? "--list" : "-list"); + command.push_back(fileName); + result = + cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, + CM_NULLPTR, cmSystemTools::OUTPUT_NONE); + } + if (!result || retVal) { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc list process for " << fileName + << " failed:\n" + << rccStdOut << "\n" + << rccStdErr << "\n"; + *errorMessage = ost.str(); + } + return false; + } + + // Parse rcc std output + { + std::istringstream ostr(rccStdOut); + std::string oline; + while (std::getline(ostr, oline)) { + oline = utilStripCR(oline); + if (!oline.empty()) { + files.push_back(oline); + } + } + } + // Parse rcc error output + { + std::istringstream estr(rccStdErr); + std::string eline; + while (std::getline(estr, eline)) { + eline = utilStripCR(eline); + if (cmHasLiteralPrefix(eline, "RCC: Error in")) { + static std::string searchString = "Cannot find file '"; + + std::string::size_type pos = eline.find(searchString); + if (pos == std::string::npos) { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc lists unparsable output:\n" + << cmQtAutoGeneratorCommon::Quoted(eline) << "\n"; + *errorMessage = ost.str(); + } + return false; + } + pos += searchString.length(); + std::string::size_type sz = eline.size() - pos - 1; + files.push_back(eline.substr(pos, sz)); + } + } + } + + return true; +} + +// - Class definitions + +const char* cmQtAutoGeneratorCommon::listSep = "@LSEP@"; + +std::string cmQtAutoGeneratorCommon::Quoted(const std::string& text) +{ + static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", + "\b", "\\b", "\f", "\\f", "\n", "\\n", + "\r", "\\r", "\t", "\\t", "\v", "\\v" }; + + std::string res = text; + for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep); + it += 2) { + cmSystemTools::ReplaceString(res, *it, *(it + 1)); + } + res = '"' + res; + res += '"'; + return res; +} + +bool cmQtAutoGeneratorCommon::RccListInputs(const std::string& qtMajorVersion, + const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage) +{ + bool allGood = false; + if (cmsys::SystemTools::FileExists(fileName.c_str())) { + if (qtMajorVersion == "4") { + allGood = RccListInputsQt4(fileName, files, errorMessage); + } else { + allGood = RccListInputsQt5(rccCommand, fileName, files, errorMessage); + } + } else { + if (errorMessage != CM_NULLPTR) { + std::ostringstream ost; + ost << "AutoRcc: Error: Rcc file does not exist:\n" + << cmQtAutoGeneratorCommon::Quoted(fileName) << "\n"; + *errorMessage = ost.str(); + } + } + return allGood; +} diff --git a/Source/cmQtAutoGeneratorCommon.h b/Source/cmQtAutoGeneratorCommon.h new file mode 100644 index 0000000..ee97b71 --- /dev/null +++ b/Source/cmQtAutoGeneratorCommon.h @@ -0,0 +1,34 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmQtAutoGeneratorCommon_h +#define cmQtAutoGeneratorCommon_h + +#include <cmConfigure.h> // IWYU pragma: keep +#include <string> +#include <vector> + +class cmGeneratorTarget; +class cmLocalGenerator; + +class cmQtAutoGeneratorCommon +{ + // - Types and statics +public: + static const char* listSep; + +public: + /// @brief Returns a the string escaped and enclosed in quotes + /// + static std::string Quoted(const std::string& text); + + /// @brief Reads the resource files list from from a .qrc file + /// @arg fileName Must be the absolute path of the .qrc file + /// @return True if the rcc file was successfully parsed + static bool RccListInputs(const std::string& qtMajorVersion, + const std::string& rccCommand, + const std::string& fileName, + std::vector<std::string>& files, + std::string* errorMessage = CM_NULLPTR); +}; + +#endif diff --git a/Source/cmQtAutoGeneratorInitializer.cxx b/Source/cmQtAutoGeneratorInitializer.cxx index a45b3d5..94cc981 100644 --- a/Source/cmQtAutoGeneratorInitializer.cxx +++ b/Source/cmQtAutoGeneratorInitializer.cxx @@ -1,6 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGeneratorInitializer.h" +#include "cmQtAutoGeneratorCommon.h" #include "cmAlgorithms.h" #include "cmCustomCommandLines.h" @@ -44,14 +45,9 @@ static void utilCopyTargetProperty(cmTarget* destinationTarget, } } -static std::string utilStripCR(std::string const& line) +inline static bool PropertyEnabled(cmSourceFile* sourceFile, const char* key) { - // Strip CR characters rcc may have printed (possibly more than one!). - std::string::size_type cr = line.find('\r'); - if (cr != line.npos) { - return line.substr(0, cr); - } - return line; + return cmSystemTools::IsOn(sourceFile->GetPropertyForUser(key)); } static std::string GetSafeProperty(cmGeneratorTarget const* target, @@ -138,21 +134,17 @@ static void AddDefinitionEscaped(cmMakefile* makefile, const char* key, key, cmOutputConverter::EscapeForCMake(cmJoin(values, ";")).c_str()); } -static void SetupSourceFiles(cmGeneratorTarget const* target, +static void AcquireScanFiles(cmGeneratorTarget const* target, std::vector<std::string>& mocUicSources, std::vector<std::string>& mocUicHeaders, std::vector<std::string>& mocSkipList, std::vector<std::string>& uicSkipList) { - cmMakefile* makefile = target->Target->GetMakefile(); - - std::vector<cmSourceFile*> srcFiles; - target->GetConfigCommonSourceFiles(srcFiles); - const bool mocTarget = target->GetPropertyAsBool("AUTOMOC"); const bool uicTarget = target->GetPropertyAsBool("AUTOUIC"); - cmFilePathChecksum fpathCheckSum(makefile); + std::vector<cmSourceFile*> srcFiles; + target->GetConfigCommonSourceFiles(srcFiles); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; @@ -163,18 +155,12 @@ static void SetupSourceFiles(cmGeneratorTarget const* target, !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { continue; } - if (cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - continue; - } const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); // Skip flags - const bool skipAll = - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")); - const bool mocSkip = - skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOMOC")); - const bool uicSkip = - skipAll || cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOUIC")); + const bool skipAll = PropertyEnabled(sf, "SKIP_AUTOGEN"); + const bool mocSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOMOC"); + const bool uicSkip = skipAll || PropertyEnabled(sf, "SKIP_AUTOUIC"); // Add file name to skip lists. // Do this even when the file is not added to the sources/headers lists // because the file name may be extracted from an other file when @@ -361,7 +347,8 @@ static void UicSetupAutoTarget( uiFileFiles.push_back(absFile); { std::string opts = sf->GetProperty("AUTOUIC_OPTIONS"); - cmSystemTools::ReplaceString(opts, ";", "@list_sep@"); + cmSystemTools::ReplaceString(opts, ";", + cmQtAutoGeneratorCommon::listSep); uiFileOptions.push_back(opts); } } @@ -469,146 +456,12 @@ static void RccMergeOptions(std::vector<std::string>& opts, opts.insert(opts.end(), extraOpts.begin(), extraOpts.end()); } -/// @brief Reads the resource files list from from a .qrc file - Qt5 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt5(cmSourceFile* sf, cmGeneratorTarget const* target, - std::vector<std::string>& depends) -{ - const std::string rccCommand = RccGetExecutable(target, "5"); - if (rccCommand.empty()) { - cmSystemTools::Error("AUTOGEN: error: rcc executable not available\n"); - return false; - } - - bool hasDashDashList = false; - // Read rcc features - { - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back("--help"); - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - CM_NULLPTR, cmSystemTools::OUTPUT_NONE); - if (result && retVal == 0 && - rccStdOut.find("--list") != std::string::npos) { - hasDashDashList = true; - } - } - // Run rcc list command - std::vector<std::string> command; - command.push_back(rccCommand); - command.push_back(hasDashDashList ? "--list" : "-list"); - - std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - command.push_back(absFile); - - std::string rccStdOut; - std::string rccStdErr; - int retVal = 0; - bool result = - cmSystemTools::RunSingleCommand(command, &rccStdOut, &rccStdErr, &retVal, - CM_NULLPTR, cmSystemTools::OUTPUT_NONE); - if (!result || retVal) { - std::ostringstream err; - err << "AUTOGEN: error: Rcc list process for " << sf->GetFullPath() - << " failed:\n" - << rccStdOut << "\n" - << rccStdErr << std::endl; - cmSystemTools::Error(err.str().c_str()); - return false; - } - - // Parse rcc list output - { - std::istringstream ostr(rccStdOut); - std::string oline; - while (std::getline(ostr, oline)) { - oline = utilStripCR(oline); - if (!oline.empty()) { - depends.push_back(oline); - } - } - } - - { - std::istringstream estr(rccStdErr); - std::string eline; - while (std::getline(estr, eline)) { - eline = utilStripCR(eline); - if (cmHasLiteralPrefix(eline, "RCC: Error in")) { - static std::string searchString = "Cannot find file '"; - - std::string::size_type pos = eline.find(searchString); - if (pos == std::string::npos) { - std::ostringstream err; - err << "AUTOGEN: error: Rcc lists unparsable output " << eline - << std::endl; - cmSystemTools::Error(err.str().c_str()); - return false; - } - pos += searchString.length(); - std::string::size_type sz = eline.size() - pos - 1; - depends.push_back(eline.substr(pos, sz)); - } - } - } - - return true; -} - -/// @brief Reads the resource files list from from a .qrc file - Qt4 version -/// @return True if the .qrc file was successfully parsed -static bool RccListInputsQt4(cmSourceFile* sf, - std::vector<std::string>& depends) -{ - // Read file into string - std::string qrcContents; - { - std::ostringstream stream; - stream << cmsys::ifstream(sf->GetFullPath().c_str()).rdbuf(); - qrcContents = stream.str(); - } - - cmsys::RegularExpression fileMatchRegex("(<file[^<]+)"); - cmsys::RegularExpression fileReplaceRegex("(^<file[^>]*>)"); - - size_t offset = 0; - while (fileMatchRegex.find(qrcContents.c_str() + offset)) { - std::string qrcEntry = fileMatchRegex.match(1); - offset += qrcEntry.size(); - { - fileReplaceRegex.find(qrcEntry); - std::string tag = fileReplaceRegex.match(1); - qrcEntry = qrcEntry.substr(tag.size()); - } - if (!cmSystemTools::FileIsFullPath(qrcEntry.c_str())) { - qrcEntry = sf->GetLocation().GetDirectory() + "/" + qrcEntry; - } - depends.push_back(qrcEntry); - } - return true; -} - -/// @brief Reads the resource files list from from a .qrc file -/// @return True if the rcc file was successfully parsed -static bool RccListInputs(const std::string& qtMajorVersion, cmSourceFile* sf, - cmGeneratorTarget const* target, - std::vector<std::string>& depends) -{ - if (qtMajorVersion == "5") { - return RccListInputsQt5(sf, target, depends); - } - return RccListInputsQt4(sf, depends); -} - static void RccSetupAutoTarget(cmGeneratorTarget const* target, const std::string& qtMajorVersion) { cmMakefile* makefile = target->Target->GetMakefile(); const bool qtMajorVersion5 = (qtMajorVersion == "5"); + const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); std::vector<std::string> _rcc_files; std::vector<std::string> _rcc_inputs; std::vector<std::string> rccFileFiles; @@ -623,53 +476,54 @@ static void RccSetupAutoTarget(cmGeneratorTarget const* target, for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - if (sf->GetExtension() == "qrc") { - const bool skip = - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) || - cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC")); - if (!skip) { - const std::string absFile = - cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - // qrc file - _rcc_files.push_back(absFile); - // qrc file entries - { - std::string entriesList; - if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - std::vector<std::string> depends; - if (RccListInputs(qtMajorVersion, sf, target, depends)) { - entriesList = cmJoin(depends, "@list_sep@"); - } else { - return; - } + if ((sf->GetExtension() == "qrc") && + !PropertyEnabled(sf, "SKIP_AUTOGEN") && + !PropertyEnabled(sf, "SKIP_AUTORCC")) { + const std::string absFile = + cmsys::SystemTools::GetRealPath(sf->GetFullPath()); + // qrc file + _rcc_files.push_back(absFile); + // qrc file entries + { + std::string entriesList = "{"; + // Read input file list only for non generated .qrc files. + if (!PropertyEnabled(sf, "GENERATED")) { + std::string error; + std::vector<std::string> files; + if (cmQtAutoGeneratorCommon::RccListInputs( + qtMajorVersion, rccCommand, absFile, files, &error)) { + entriesList += cmJoin(files, cmQtAutoGeneratorCommon::listSep); + } else { + cmSystemTools::Error(error.c_str()); } - _rcc_inputs.push_back(entriesList); } - // rcc options for this qrc file - { - // Merged target and file options - std::vector<std::string> rccOptions(rccOptionsTarget); - if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { - std::vector<std::string> optsVec; - cmSystemTools::ExpandListArgument(prop, optsVec); - RccMergeOptions(rccOptions, optsVec, qtMajorVersion5); - } - // Only store non empty options lists - if (!rccOptions.empty()) { - rccFileFiles.push_back(absFile); - rccFileOptions.push_back(cmJoin(rccOptions, "@list_sep@")); - } + entriesList += "}"; + _rcc_inputs.push_back(entriesList); + } + // rcc options for this qrc file + { + // Merged target and file options + std::vector<std::string> rccOptions(rccOptionsTarget); + if (const char* prop = sf->GetProperty("AUTORCC_OPTIONS")) { + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(prop, optsVec); + RccMergeOptions(rccOptions, optsVec, qtMajorVersion5); + } + // Only store non empty options lists + if (!rccOptions.empty()) { + rccFileFiles.push_back(absFile); + rccFileOptions.push_back( + cmJoin(rccOptions, cmQtAutoGeneratorCommon::listSep)); } } } } + AddDefinitionEscaped(makefile, "_qt_rcc_executable", rccCommand); AddDefinitionEscaped(makefile, "_rcc_files", _rcc_files); AddDefinitionEscaped(makefile, "_rcc_inputs", _rcc_inputs); AddDefinitionEscaped(makefile, "_rcc_options_files", rccFileFiles); AddDefinitionEscaped(makefile, "_rcc_options_options", rccFileOptions); - AddDefinitionEscaped(makefile, "_qt_rcc_executable", - RccGetExecutable(target, qtMajorVersion)); } void cmQtAutoGeneratorInitializer::InitializeAutogenSources( @@ -691,12 +545,17 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( cmMakefile* makefile = target->Target->GetMakefile(); // Create a custom target for running generators at buildtime + const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); + const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); + const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string autogenBuildDir = GetAutogenTargetBuildDir(target); const std::string workingDirectory = cmSystemTools::CollapseFullPath("", makefile->GetCurrentBinaryDirectory()); const std::string qtMajorVersion = GetQtMajorVersion(target); - std::vector<std::string> autogenOutputFiles; + const std::string rccCommand = RccGetExecutable(target, qtMajorVersion); + std::vector<std::string> autogenDepends; + std::vector<std::string> autogenProvides; // Remove old settings on cleanup { @@ -706,32 +565,6 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( false); } - // Create autogen target build directory and add it to the clean files - cmSystemTools::MakeDirectory(autogenBuildDir); - makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", - autogenBuildDir.c_str(), false); - - if (target->GetPropertyAsBool("AUTOMOC") || - target->GetPropertyAsBool("AUTOUIC")) { - // Create autogen target includes directory and - // add it to the origin target INCLUDE_DIRECTORIES - const std::string incsDir = autogenBuildDir + "include"; - cmSystemTools::MakeDirectory(incsDir); - target->AddIncludeDirectory(incsDir, true); - } - - if (target->GetPropertyAsBool("AUTOMOC")) { - // Register moc compilation file as generated - autogenOutputFiles.push_back(autogenBuildDir + "moc_compilation.cpp"); - } - - // Initialize autogen target dependencies - std::vector<std::string> depends; - if (const char* autogenDepends = - target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { - cmSystemTools::ExpandListArgument(autogenDepends, depends); - } - // Compose command lines cmCustomCommandLines commandLines; { @@ -748,13 +581,13 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( std::string autogenComment; { std::vector<std::string> toolNames; - if (target->GetPropertyAsBool("AUTOMOC")) { + if (mocEnabled) { toolNames.push_back("MOC"); } - if (target->GetPropertyAsBool("AUTOUIC")) { + if (uicEnabled) { toolNames.push_back("UIC"); } - if (target->GetPropertyAsBool("AUTORCC")) { + if (rccEnabled) { toolNames.push_back("RCC"); } @@ -770,6 +603,24 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( autogenComment = "Automatic " + tools + " for target " + target->GetName(); } + // Create autogen target build directory and add it to the clean files + cmSystemTools::MakeDirectory(autogenBuildDir); + makefile->AppendProperty("ADDITIONAL_MAKE_CLEAN_FILES", + autogenBuildDir.c_str(), false); + + // Create autogen target includes directory and + // add it to the origin target INCLUDE_DIRECTORIES + if (mocEnabled || uicEnabled) { + const std::string incsDir = autogenBuildDir + "include"; + cmSystemTools::MakeDirectory(incsDir); + target->AddIncludeDirectory(incsDir, true); + } + + // Register moc compilation file as generated + if (mocEnabled) { + autogenProvides.push_back(autogenBuildDir + "moc_compilation.cpp"); + } + #if defined(_WIN32) && !defined(__CYGWIN__) bool usePRE_BUILD = false; cmGlobalGenerator* gg = lg->GetGlobalGenerator(); @@ -781,65 +632,100 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( // This also works around a VS 11 bug that may skip updating the target: // https://connect.microsoft.com/VisualStudio/feedback/details/769495 usePRE_BUILD = vsgg->GetVersion() >= cmGlobalVisualStudioGenerator::VS7; - if (usePRE_BUILD) { - // If the autogen target depends on an other target - // don't use PRE_BUILD - for (std::vector<std::string>::iterator it = depends.begin(); - it != depends.end(); ++it) { - if (!makefile->FindTargetToUse(it->c_str())) { - usePRE_BUILD = false; - break; - } - } - } } #endif - if (target->GetPropertyAsBool("AUTORCC")) { + // Initialize autogen target dependencies + if (const char* deps = target->GetProperty("AUTOGEN_TARGET_DEPENDS")) { + cmSystemTools::ExpandListArgument(deps, autogenDepends); + } + // Add link library targets to the autogen dependencies + { + const cmTarget::LinkLibraryVectorType& libVec = + target->Target->GetOriginalLinkLibraries(); + for (cmTarget::LinkLibraryVectorType::const_iterator it = libVec.begin(); + it != libVec.end(); ++it) { + const std::string& libName = it->first; + if (makefile->FindTargetToUse(libName) != CM_NULLPTR) { + autogenDepends.push_back(libName); + } + } + } + { cmFilePathChecksum fpathCheckSum(makefile); + // Iterate over all source files std::vector<cmSourceFile*> srcFiles; target->GetConfigCommonSourceFiles(srcFiles); for (std::vector<cmSourceFile*>::const_iterator fileIt = srcFiles.begin(); fileIt != srcFiles.end(); ++fileIt) { cmSourceFile* sf = *fileIt; - if (sf->GetExtension() == "qrc" && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTOGEN")) && - !cmSystemTools::IsOn(sf->GetPropertyForUser("SKIP_AUTORCC"))) { - { + if (!PropertyEnabled(sf, "SKIP_AUTOGEN")) { + const std::string ext = sf->GetExtension(); + // Add generated file that will be scanned by moc or uic to + // the dependencies + if (mocEnabled || uicEnabled) { + const cmSystemTools::FileFormat fileType = + cmSystemTools::GetFileFormat(ext.c_str()); + if ((fileType == cmSystemTools::CXX_FILE_FORMAT) || + (fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + if (PropertyEnabled(sf, "GENERATED")) { + if ((mocEnabled && !PropertyEnabled(sf, "SKIP_AUTOMOC")) || + (uicEnabled && !PropertyEnabled(sf, "SKIP_AUTOUIC"))) { + autogenDepends.push_back( + cmsys::SystemTools::GetRealPath(sf->GetFullPath())); +#if defined(_WIN32) && !defined(__CYGWIN__) + // Cannot use PRE_BUILD with generated files + usePRE_BUILD = false; +#endif + } + } + } + } + // Process rcc enabled files + if (rccEnabled && (ext == "qrc") && + !PropertyEnabled(sf, "SKIP_AUTORCC")) { const std::string absFile = cmsys::SystemTools::GetRealPath(sf->GetFullPath()); - // Run cmake again when .qrc file changes - makefile->AddCMakeDependFile(absFile); - - std::string rccOutputFile = autogenBuildDir; - rccOutputFile += fpathCheckSum.getPart(absFile); - rccOutputFile += "/qrc_"; - rccOutputFile += - cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); - rccOutputFile += ".cpp"; - - // Add rcc output file to origin target sources - cmSourceFile* gf = makefile->GetOrCreateSource(rccOutputFile, true); - gf->SetProperty("SKIP_AUTOGEN", "On"); - target->AddSource(rccOutputFile); - // Register rcc output file as generated - autogenOutputFiles.push_back(rccOutputFile); - } - if (lg->GetGlobalGenerator()->GetName() == "Ninja" -#if defined(_WIN32) && !defined(__CYGWIN__) - || usePRE_BUILD -#endif - ) { - if (!cmSystemTools::IsOn(sf->GetPropertyForUser("GENERATED"))) { - RccListInputs(qtMajorVersion, sf, target, depends); + // Compose rcc output file name + { + std::string rccOut = autogenBuildDir; + rccOut += fpathCheckSum.getPart(absFile); + rccOut += "/qrc_"; + rccOut += + cmsys::SystemTools::GetFilenameWithoutLastExtension(absFile); + rccOut += ".cpp"; + + // Register rcc output file as generated + autogenProvides.push_back(rccOut); + + // Add rcc output file to origin target sources + cmSourceFile* gf = makefile->GetOrCreateSource(rccOut, true); + gf->SetProperty("SKIP_AUTOGEN", "On"); + target->AddSource(rccOut); + } + + if (PropertyEnabled(sf, "GENERATED")) { + // Add generated qrc file to the dependencies + autogenDepends.push_back(absFile); + } else { + // Run cmake again when .qrc file changes + makefile->AddCMakeDependFile(absFile); + + // Add the qrc input files to the dependencies + std::string error; + if (!cmQtAutoGeneratorCommon::RccListInputs( + qtMajorVersion, rccCommand, absFile, autogenDepends, + &error)) { + cmSystemTools::Error(error.c_str()); + } + } #if defined(_WIN32) && !defined(__CYGWIN__) - // Cannot use PRE_BUILD because the resource files themselves - // may not be sources within the target so VS may not know the - // target needs to re-build at all. - usePRE_BUILD = false; + // Cannot use PRE_BUILD because the resource files themselves + // may not be sources within the target so VS may not know the + // target needs to re-build at all. + usePRE_BUILD = false; #endif - } } } } @@ -847,12 +733,21 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( #if defined(_WIN32) && !defined(__CYGWIN__) if (usePRE_BUILD) { + // If the autogen target depends on an other target don't use PRE_BUILD + for (std::vector<std::string>::iterator it = autogenDepends.begin(); + it != autogenDepends.end(); ++it) { + if (makefile->FindTargetToUse(*it) != CM_NULLPTR) { + usePRE_BUILD = false; + break; + } + } + } + if (usePRE_BUILD) { // Add the pre-build command directly to bypass the OBJECT_LIBRARY // rejection in cmMakefile::AddCustomCommandToTarget because we know // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. std::vector<std::string> no_output; - std::vector<std::string> no_byproducts; - cmCustomCommand cc(makefile, no_output, no_byproducts, depends, + cmCustomCommand cc(makefile, no_output, autogenProvides, autogenDepends, commandLines, autogenComment.c_str(), workingDirectory.c_str()); cc.SetEscapeOldStyle(false); @@ -863,7 +758,7 @@ void cmQtAutoGeneratorInitializer::InitializeAutogenTarget( { cmTarget* autogenTarget = makefile->AddUtilityCommand( autogenTargetName, true, workingDirectory.c_str(), - /*byproducts=*/autogenOutputFiles, depends, commandLines, false, + /*byproducts=*/autogenProvides, autogenDepends, commandLines, false, autogenComment.c_str()); cmGeneratorTarget* gt = new cmGeneratorTarget(autogenTarget, lg); @@ -900,38 +795,37 @@ void cmQtAutoGeneratorInitializer::SetupAutoGenerateTarget( std::map<std::string, std::string> configMocDefines; std::map<std::string, std::string> configUicOptions; { - // create a custom target for running generators at buildtime: + const bool mocEnabled = target->GetPropertyAsBool("AUTOMOC"); + const bool uicEnabled = target->GetPropertyAsBool("AUTOUIC"); + const bool rccEnabled = target->GetPropertyAsBool("AUTORCC"); const std::string autogenTargetName = GetAutogenTargetName(target); const std::string qtMajorVersion = GetQtMajorVersion(target); - AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); - AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); - AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); - std::vector<std::string> _sources; std::vector<std::string> _headers; - std::vector<std::string> mocSkipList; - std::vector<std::string> uicSkipList; - if (target->GetPropertyAsBool("AUTOMOC") || - target->GetPropertyAsBool("AUTOUIC") || - target->GetPropertyAsBool("AUTORCC")) { - SetupSourceFiles(target, _sources, _headers, mocSkipList, uicSkipList); + if (mocEnabled || uicEnabled || rccEnabled) { + std::vector<std::string> mocSkipList; + std::vector<std::string> uicSkipList; + AcquireScanFiles(target, _sources, _headers, mocSkipList, uicSkipList); + if (mocEnabled) { + MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, + mocSkipList, configMocIncludes, configMocDefines); + } + if (uicEnabled) { + UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, + configUicOptions); + } + if (rccEnabled) { + RccSetupAutoTarget(target, qtMajorVersion); + } } + + AddDefinitionEscaped(makefile, "_autogen_target_name", autogenTargetName); + AddDefinitionEscaped(makefile, "_origin_target_name", target->GetName()); + AddDefinitionEscaped(makefile, "_qt_version_major", qtMajorVersion); AddDefinitionEscaped(makefile, "_sources", _sources); AddDefinitionEscaped(makefile, "_headers", _headers); - - if (target->GetPropertyAsBool("AUTOMOC")) { - MocSetupAutoTarget(target, autogenTargetName, qtMajorVersion, - mocSkipList, configMocIncludes, configMocDefines); - } - if (target->GetPropertyAsBool("AUTOUIC")) { - UicSetupAutoTarget(target, qtMajorVersion, uicSkipList, - configUicOptions); - } - if (target->GetPropertyAsBool("AUTORCC")) { - RccSetupAutoTarget(target, qtMajorVersion); - } } // Generate config file diff --git a/Source/cmQtAutoGenerators.cxx b/Source/cmQtAutoGenerators.cxx index c83f9a9..246dd8d 100644 --- a/Source/cmQtAutoGenerators.cxx +++ b/Source/cmQtAutoGenerators.cxx @@ -1,6 +1,7 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenerators.h" +#include "cmQtAutoGeneratorCommon.h" #include <algorithm> #include <assert.h> @@ -36,23 +37,9 @@ static const char* SettingsKeyRcc = "AM_RCC_OLD_SETTINGS"; // -- Static functions -/** - * @brief Returns a the string escaped and enclosed in quotes - */ -static std::string Quoted(const std::string& text) +inline static std::string Quoted(const std::string& text) { - static const char* rep[18] = { "\\", "\\\\", "\"", "\\\"", "\a", "\\a", - "\b", "\\b", "\f", "\\f", "\n", "\\n", - "\r", "\\r", "\t", "\\t", "\v", "\\v" }; - - std::string res = text; - for (const char* const* it = cmArrayBegin(rep); it != cmArrayEnd(rep); - it += 2) { - cmSystemTools::ReplaceString(res, *it, *(it + 1)); - } - res = '"' + res; - res += '"'; - return res; + return cmQtAutoGeneratorCommon::Quoted(text); } static void InfoGet(cmMakefile* makefile, const char* key, std::string& value) @@ -138,13 +125,19 @@ static bool FileNameIsUnique(const std::string& filePath, return true; } -static std::string ReadAll(const std::string& filename) +static bool ReadAll(std::string& content, const std::string& filename) { - cmsys::ifstream file(filename.c_str()); - std::ostringstream stream; - stream << file.rdbuf(); - file.close(); - return stream.str(); + bool success = false; + { + cmsys::ifstream ifs(filename.c_str()); + if (ifs) { + std::ostringstream osst; + osst << ifs.rdbuf(); + content = osst.str(); + success = true; + } + } + return success; } /** @@ -178,7 +171,7 @@ static std::string JoinOptionsMap( for (std::map<std::string, std::string>::const_iterator it = opts.begin(); it != opts.end(); ++it) { if (it != opts.begin()) { - result += "@list_sep@"; + result += cmQtAutoGeneratorCommon::listSep; } result += it->first; result += "==="; @@ -402,7 +395,8 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( } else { this->LogError( "AutoMoc: Error: AUTOMOC_DEPEND_FILTERS list size is not " - "a multiple of 2"); + "a multiple of 2 in:\n" + + Quoted(filename)); return false; } } @@ -424,13 +418,14 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( fileIt = uicFilesVec.begin(), optionIt = uicOptionsVec.begin(); fileIt != uicFilesVec.end(); ++fileIt, ++optionIt) { - cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); + cmSystemTools::ReplaceString(*optionIt, + cmQtAutoGeneratorCommon::listSep, ";"); this->UicOptions[*fileIt] = *optionIt; } } else { this->LogError( - "AutoGen: Error: Uic files/options lists size missmatch in: " + - filename); + "AutoGen: Error: Uic files/options lists size missmatch in:\n" + + Quoted(filename)); return false; } } @@ -439,47 +434,53 @@ bool cmQtAutoGenerators::ReadAutogenInfoFile( // - Rcc if (this->RccEnabled()) { InfoGet(makefile, "AM_RCC_SOURCES", this->RccSources); + // File options { std::vector<std::string> rccFilesVec; std::vector<std::string> rccOptionsVec; InfoGet(makefile, "AM_RCC_OPTIONS_FILES", rccFilesVec); InfoGet(makefile, "AM_RCC_OPTIONS_OPTIONS", rccOptionsVec); - if (rccFilesVec.size() != rccOptionsVec.size()) { + if (rccFilesVec.size() == rccOptionsVec.size()) { + for (std::vector<std::string>::iterator + fileIt = rccFilesVec.begin(), + optionIt = rccOptionsVec.begin(); + fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) { + // Replace item separator + cmSystemTools::ReplaceString(*optionIt, + cmQtAutoGeneratorCommon::listSep, ";"); + this->RccOptions[*fileIt] = *optionIt; + } + } else { this->LogError( - "AutoGen: Error: RCC files/options lists size missmatch in: " + - filename); + "AutoGen: Error: RCC files/options lists size missmatch in:\n" + + Quoted(filename)); return false; } - for (std::vector<std::string>::iterator fileIt = rccFilesVec.begin(), - optionIt = rccOptionsVec.begin(); - fileIt != rccFilesVec.end(); ++fileIt, ++optionIt) { - cmSystemTools::ReplaceString(*optionIt, "@list_sep@", ";"); - this->RccOptions[*fileIt] = *optionIt; - } } + // File lists { std::vector<std::string> rccInputLists; InfoGet(makefile, "AM_RCC_INPUTS", rccInputLists); - - // qrc files in the end of the list may have been empty - if (rccInputLists.size() < this->RccSources.size()) { - rccInputLists.resize(this->RccSources.size()); - } - if (this->RccSources.size() != rccInputLists.size()) { + if (this->RccSources.size() == rccInputLists.size()) { + for (std::vector<std::string>::iterator + fileIt = this->RccSources.begin(), + inputIt = rccInputLists.begin(); + fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { + // Remove braces + *inputIt = inputIt->substr(1, inputIt->size() - 2); + // Replace item separator + cmSystemTools::ReplaceString(*inputIt, + cmQtAutoGeneratorCommon::listSep, ";"); + std::vector<std::string> rccInputFiles; + cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); + this->RccInputs[*fileIt] = rccInputFiles; + } + } else { this->LogError( - "AutoGen: Error: RCC sources/inputs lists size missmatch in: " + - filename); + "AutoGen: Error: RCC sources/inputs lists size missmatch in:\n" + + Quoted(filename)); return false; } - for (std::vector<std::string>::iterator - fileIt = this->RccSources.begin(), - inputIt = rccInputLists.begin(); - fileIt != this->RccSources.end(); ++fileIt, ++inputIt) { - cmSystemTools::ReplaceString(*inputIt, "@list_sep@", ";"); - std::vector<std::string> rccInputFiles; - cmSystemTools::ExpandListArgument(*inputIt, rccInputFiles); - this->RccInputs[*fileIt] = rccInputFiles; - } } } @@ -687,8 +688,10 @@ bool cmQtAutoGenerators::RunAutogen() uicHeaderFiles.insert(headerName); } } - this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, - mocsNotIncluded, mocDepends, uisIncluded); + if (!this->ParseHeaders(mocHeaderFiles, uicHeaderFiles, mocsIncluded, + mocsNotIncluded, mocDepends, uisIncluded)) { + return false; + }; // Generate files if (!this->MocGenerateAll(mocsIncluded, mocsNotIncluded, mocDepends)) { @@ -804,23 +807,29 @@ bool cmQtAutoGenerators::ParseSourceFile( std::map<std::string, std::set<std::string> >& mocDepends, std::map<std::string, std::vector<std::string> >& uisIncluded, bool relaxed) { - bool success = true; - const std::string contentText = ReadAll(absFilename); - if (contentText.empty()) { - std::ostringstream ost; - ost << "AutoGen: Warning: " << absFilename << "\n" - << "The file is empty\n"; - this->LogWarning(ost.str()); - } else { - // Parse source contents for MOC - if (success && !this->MocSkip(absFilename)) { - success = this->MocParseSourceContent(absFilename, contentText, - mocsIncluded, mocDepends, relaxed); - } - // Parse source contents for UIC - if (success && !this->UicSkip(absFilename)) { - this->UicParseContent(absFilename, contentText, uisIncluded); + std::string contentText; + bool success = ReadAll(contentText, absFilename); + if (success) { + if (!contentText.empty()) { + // Parse source contents for MOC + if (success && !this->MocSkip(absFilename)) { + success = this->MocParseSourceContent( + absFilename, contentText, mocsIncluded, mocDepends, relaxed); + } + // Parse source contents for UIC + if (success && !this->UicSkip(absFilename)) { + this->UicParseContent(absFilename, contentText, uisIncluded); + } + } else { + std::ostringstream ost; + ost << "AutoGen: Warning: The file is empty:\n" + << Quoted(absFilename) << "\n"; + this->LogWarning(ost.str()); } + } else { + std::ostringstream ost; + ost << "AutoGen: Error: Could not read file:\n" << Quoted(absFilename); + this->LogError(ost.str()); } return success; } @@ -1083,7 +1092,7 @@ void cmQtAutoGenerators::SearchHeadersForSourceFile( } } -void cmQtAutoGenerators::ParseHeaders( +bool cmQtAutoGenerators::ParseHeaders( const std::set<std::string>& mocHeaderFiles, const std::set<std::string>& uicHeaderFiles, const std::map<std::string, std::string>& mocsIncluded, @@ -1091,6 +1100,7 @@ void cmQtAutoGenerators::ParseHeaders( std::map<std::string, std::set<std::string> >& mocDepends, std::map<std::string, std::vector<std::string> >& uisIncluded) { + bool success = true; // Merged header files list to read files only once std::set<std::string> headerFiles; headerFiles.insert(mocHeaderFiles.begin(), mocHeaderFiles.end()); @@ -1099,20 +1109,28 @@ void cmQtAutoGenerators::ParseHeaders( for (std::set<std::string>::const_iterator hIt = headerFiles.begin(); hIt != headerFiles.end(); ++hIt) { const std::string& headerName = *hIt; - const std::string contentText = ReadAll(headerName); - - // Parse header content for MOC - if ((mocHeaderFiles.find(headerName) != mocHeaderFiles.end()) && - (mocsIncluded.find(headerName) == mocsIncluded.end())) { - this->MocParseHeaderContent(headerName, contentText, mocsNotIncluded, - mocDepends); - } - - // Parse header content for UIC - if (uicHeaderFiles.find(headerName) != uicHeaderFiles.end()) { - this->UicParseContent(headerName, contentText, uisIncluded); + std::string contentText; + if (ReadAll(contentText, headerName)) { + // Parse header content for MOC + if ((mocHeaderFiles.find(headerName) != mocHeaderFiles.end()) && + (mocsIncluded.find(headerName) == mocsIncluded.end())) { + this->MocParseHeaderContent(headerName, contentText, mocsNotIncluded, + mocDepends); + } + // Parse header content for UIC + if (uicHeaderFiles.find(headerName) != uicHeaderFiles.end()) { + this->UicParseContent(headerName, contentText, uisIncluded); + } + } else { + std::ostringstream ost; + ost << "AutoGen: Error: Could not read header file:\n" + << Quoted(headerName); + this->LogError(ost.str()); + success = false; + break; } } + return success; } bool cmQtAutoGenerators::MocGenerateAll( @@ -1195,8 +1213,12 @@ bool cmQtAutoGenerators::MocGenerateAll( // Check if the content of moc_compilation.cpp changed { - const std::string oldContents = ReadAll(this->MocCppFilenameAbs); - mocCompChanged = (oldContents != automocSource); + std::string oldContents; + if (ReadAll(oldContents, this->MocCppFilenameAbs)) { + mocCompChanged = (oldContents != automocSource); + } else { + mocCompChanged = true; + } } bool success = true; @@ -1290,18 +1312,12 @@ bool cmQtAutoGenerators::MocGenerateFile( cmd.push_back(mocFileAbs); cmd.push_back(sourceFile); - // Log moc command - if (this->Verbose) { - this->LogCommand(cmd); - } - // Execute moc command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + mocGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1313,9 +1329,6 @@ bool cmQtAutoGenerators::MocGenerateFile( } cmSystemTools::RemoveFile(mocFileAbs); this->RunMocFailed = true; - } else { - // Success - mocGenerated = true; } } else { // Parent directory creation failed @@ -1470,18 +1483,11 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, cmd.push_back(uicFileAbs); cmd.push_back(uiInputFile); - // Log command - if (this->Verbose) { - this->LogCommand(cmd); - } - - // Execute command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + uicGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1494,9 +1500,6 @@ bool cmQtAutoGenerators::UicGenerateFile(const std::string& realName, } cmSystemTools::RemoveFile(uicFileAbs); this->RunUicFailed = true; - } else { - // Success - uicGenerated = true; } } else { // Parent directory creation failed @@ -1566,13 +1569,30 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, // Test if the resources list file is newer than build file generateRcc = FileAbsentOrOlder(rccBuildFile, rccInputFile); if (!generateRcc) { - // Test if any resource file is newer than the build file - const std::vector<std::string>& files = this->RccInputs[rccInputFile]; - for (std::vector<std::string>::const_iterator it = files.begin(); - it != files.end(); ++it) { - if (FileAbsentOrOlder(rccBuildFile, *it)) { - generateRcc = true; - break; + // Acquire input file list + std::vector<std::string> readFiles; + const std::vector<std::string>* files = &this->RccInputs[rccInputFile]; + if (files->empty()) { + // Read input file list from qrc file + std::string error; + if (cmQtAutoGeneratorCommon::RccListInputs( + this->QtMajorVersion, this->RccExecutable, rccInputFile, + readFiles, &error)) { + files = &readFiles; + } else { + files = CM_NULLPTR; + this->LogError(error); + this->RunRccFailed = true; + } + } + // Test if any input file is newer than the build file + if (files != CM_NULLPTR) { + for (std::vector<std::string>::const_iterator it = files->begin(); + it != files->end(); ++it) { + if (FileAbsentOrOlder(rccBuildFile, *it)) { + generateRcc = true; + break; + } } } } @@ -1610,17 +1630,11 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, cmd.push_back(rccBuildFile); cmd.push_back(rccInputFile); - // Log command - if (this->Verbose) { - this->LogCommand(cmd); - } - - // Execute command - bool res = false; - int retVal = 0; std::string output; - res = cmSystemTools::RunSingleCommand(cmd, &output, &output, &retVal); - if (!res || (retVal != 0)) { + if (this->RunCommand(cmd, output)) { + // Success + rccGenerated = true; + } else { // Command failed { std::ostringstream ost; @@ -1632,9 +1646,6 @@ bool cmQtAutoGenerators::RccGenerateFile(const std::string& rccInputFile, } cmSystemTools::RemoveFile(rccBuildFile); this->RunRccFailed = true; - } else { - // Success - rccGenerated = true; } } else { // Parent directory creation failed @@ -1712,7 +1723,18 @@ void cmQtAutoGenerators::LogError(const std::string& message) const void cmQtAutoGenerators::LogCommand( const std::vector<std::string>& command) const { - this->LogInfo(cmJoin(command, " ")); + std::vector<std::string> cmdEscaped; + typedef std::vector<std::string>::const_iterator Iter; + for (Iter cit = command.begin(); cit != command.end(); ++cit) { + const std::string cesc = Quoted(*cit); + if ((cesc.size() > (cit->size() + 2)) || + (cesc.find(' ') != std::string::npos)) { + cmdEscaped.push_back(cesc); + } else { + cmdEscaped.push_back(*cit); + } + } + this->LogInfo(cmJoin(cmdEscaped, " ")); } /** @@ -1762,6 +1784,41 @@ std::string cmQtAutoGenerators::ChecksumedPath(const std::string& sourceFile, } /** + * @brief Generates the parent directory of the given file on demand + * @return True on success + */ +bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) const +{ + bool success = true; + const std::string dirName = cmSystemTools::GetFilenamePath(filename); + if (!dirName.empty()) { + success = cmsys::SystemTools::MakeDirectory(dirName); + if (!success) { + this->LogError("AutoGen: Error: Directory creation failed: " + dirName); + } + } + return success; +} + +/** + * @brief Runs a command and returns true on success + * @return True on success + */ +bool cmQtAutoGenerators::RunCommand(const std::vector<std::string>& command, + std::string& output) const +{ + // Log command + if (this->Verbose) { + this->LogCommand(command); + } + // Execute command + int retVal = 0; + bool res = + cmSystemTools::RunSingleCommand(command, &output, &output, &retVal); + return (res && (retVal == 0)); +} + +/** * @brief Tries to find the header file to the given file base path by * appending different header extensions * @return True on success @@ -1835,20 +1892,3 @@ bool cmQtAutoGenerators::MocFindIncludedFile( } return success; } - -/** - * @brief Generates the parent directory of the given file on demand - * @return True on success - */ -bool cmQtAutoGenerators::MakeParentDirectory(const std::string& filename) const -{ - bool success = true; - const std::string dirName = cmSystemTools::GetFilenamePath(filename); - if (!dirName.empty()) { - success = cmsys::SystemTools::MakeDirectory(dirName); - if (!success) { - this->LogError("AutoGen: Error: Directory creation failed: " + dirName); - } - } - return success; -} diff --git a/Source/cmQtAutoGenerators.h b/Source/cmQtAutoGenerators.h index 3bff2b2..ee046de 100644 --- a/Source/cmQtAutoGenerators.h +++ b/Source/cmQtAutoGenerators.h @@ -78,7 +78,7 @@ private: std::set<std::string>& mocHeaderFiles, std::set<std::string>& uicHeaderFiles) const; - void ParseHeaders( + bool ParseHeaders( const std::set<std::string>& mocHeaderFiles, const std::set<std::string>& uicHeaderFiles, const std::map<std::string, std::string>& mocsIncluded, @@ -142,6 +142,8 @@ private: const char* basePrefix, const char* baseSuffix) const; bool MakeParentDirectory(const std::string& filename) const; + bool RunCommand(const std::vector<std::string>& command, + std::string& output) const; bool FindHeader(std::string& header, const std::string& testBasePath) const; diff --git a/Source/cmStateTypes.h b/Source/cmStateTypes.h index 2c974c1..da14cdb 100644 --- a/Source/cmStateTypes.h +++ b/Source/cmStateTypes.h @@ -27,6 +27,9 @@ enum SnapshotType VariableScopeType }; +// There are multiple overlapping ranges represented here. Be aware that adding +// a value to this enumeration may cause failures in numerous places which +// assume details about the ordering. enum TargetType { EXECUTABLE, diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index c360c19..e3c7b63 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -230,6 +230,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, this->SetPropertyDefault("INSTALL_NAME_DIR", CM_NULLPTR); this->SetPropertyDefault("INSTALL_RPATH", ""); this->SetPropertyDefault("INSTALL_RPATH_USE_LINK_PATH", "OFF"); + this->SetPropertyDefault("INTERPROCEDURAL_OPTIMIZATION", CM_NULLPTR); this->SetPropertyDefault("SKIP_BUILD_RPATH", "OFF"); this->SetPropertyDefault("BUILD_WITH_INSTALL_RPATH", "OFF"); this->SetPropertyDefault("ARCHIVE_OUTPUT_DIRECTORY", CM_NULLPTR); diff --git a/Source/cmWorkingDirectory.cxx b/Source/cmWorkingDirectory.cxx new file mode 100644 index 0000000..99c9ba8 --- /dev/null +++ b/Source/cmWorkingDirectory.cxx @@ -0,0 +1,24 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmWorkingDirectory.h" + +#include "cmSystemTools.h" + +cmWorkingDirectory::cmWorkingDirectory(std::string const& newdir) +{ + this->OldDir = cmSystemTools::GetCurrentWorkingDirectory(); + cmSystemTools::ChangeDirectory(newdir); +} + +cmWorkingDirectory::~cmWorkingDirectory() +{ + this->Pop(); +} + +void cmWorkingDirectory::Pop() +{ + if (!this->OldDir.empty()) { + cmSystemTools::ChangeDirectory(this->OldDir); + this->OldDir.clear(); + } +} diff --git a/Source/cmWorkingDirectory.h b/Source/cmWorkingDirectory.h new file mode 100644 index 0000000..af0fd44 --- /dev/null +++ b/Source/cmWorkingDirectory.h @@ -0,0 +1,25 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#ifndef cmWorkingDirectory_h +#define cmWorkingDirectory_h + +#include <cmConfigure.h> // IWYU pragma: keep + +#include <string> + +/** \class cmWorkingDirectory + * \brief An RAII class to manipulate the working directory. + */ +class cmWorkingDirectory +{ +public: + cmWorkingDirectory(std::string const& newdir); + ~cmWorkingDirectory(); + + void Pop(); + +private: + std::string OldDir; +}; + +#endif diff --git a/Source/cmake.cxx b/Source/cmake.cxx index b2384cd..3af3be6 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -23,6 +23,7 @@ #include "cmTargetLinkLibraryType.h" #include "cmUtils.hxx" #include "cmVersionConfig.h" +#include "cmWorkingDirectory.h" #include "cm_auto_ptr.hxx" #if defined(CMAKE_BUILD_WITH_CMAKE) @@ -2199,24 +2200,23 @@ int cmake::GetSystemInformation(std::vector<std::string>& args) resultFile += "/__cmake_systeminformation/results.txt"; } - // now run cmake on the CMakeLists file - cmSystemTools::ChangeDirectory(destPath); - std::vector<std::string> args2; - args2.push_back(args[0]); - args2.push_back(destPath); - std::string resultArg = "-DRESULT_FILE="; - resultArg += resultFile; - args2.push_back(resultArg); - int res = this->Run(args2, false); + { + // now run cmake on the CMakeLists file + cmWorkingDirectory workdir(destPath); + std::vector<std::string> args2; + args2.push_back(args[0]); + args2.push_back(destPath); + std::string resultArg = "-DRESULT_FILE="; + resultArg += resultFile; + args2.push_back(resultArg); + int res = this->Run(args2, false); - if (res != 0) { - std::cerr << "Error: --system-information failed on internal CMake!\n"; - return res; + if (res != 0) { + std::cerr << "Error: --system-information failed on internal CMake!\n"; + return res; + } } - // change back to the original directory - cmSystemTools::ChangeDirectory(cwd); - // echo results to stdout if needed if (writeToStdout) { FILE* fin = cmsys::SystemTools::Fopen(resultFile, "r"); diff --git a/Tests/CheckFortran.cmake b/Tests/CheckFortran.cmake index 93990ad..b1652ba 100644 --- a/Tests/CheckFortran.cmake +++ b/Tests/CheckFortran.cmake @@ -18,6 +18,8 @@ file(WRITE \"\${CMAKE_CURRENT_BINARY_DIR}/result.cmake\" execute_process( WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/CheckFortran COMMAND ${CMAKE_COMMAND} . -G ${CMAKE_GENERATOR} + -A "${CMAKE_GENERATOR_PLATFORM}" + -T "${CMAKE_GENERATOR_TOOLSET}" OUTPUT_VARIABLE output ERROR_VARIABLE output RESULT_VARIABLE result diff --git a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt index d134b96..420d7a9 100644 --- a/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt +++ b/Tests/CudaOnly/SeparateCompilation/CMakeLists.txt @@ -12,22 +12,22 @@ project (CudaOnlySeparateCompilation CUDA) string(APPEND CMAKE_CUDA_FLAGS " -gencode arch=compute_30,code=compute_30") set(CMAKE_CXX_STANDARD 11) set(CMAKE_CUDA_STANDARD 11) -add_library(CUDASerarateLibA STATIC file1.cu file2.cu file3.cu) +add_library(CUDASeparateLibA STATIC file1.cu file2.cu file3.cu) #Having file4/file5 in a shared library causes serious problems #with the nvcc linker and it will generate bad entries that will #cause a segv when trying to run the executable # -add_library(CUDASerarateLibB STATIC file4.cu file5.cu) -target_link_libraries(CUDASerarateLibB PRIVATE CUDASerarateLibA) +add_library(CUDASeparateLibB STATIC file4.cu file5.cu) +target_link_libraries(CUDASeparateLibB PRIVATE CUDASeparateLibA) add_executable(CudaOnlySeparateCompilation main.cu) -target_link_libraries(CudaOnlySeparateCompilation PRIVATE CUDASerarateLibB) +target_link_libraries(CudaOnlySeparateCompilation PRIVATE CUDASeparateLibB) -set_target_properties( CUDASerarateLibA - CUDASerarateLibB +set_target_properties( CUDASeparateLibA + CUDASeparateLibB PROPERTIES CUDA_SEPARABLE_COMPILATION ON) -set_target_properties( CUDASerarateLibA - CUDASerarateLibB +set_target_properties( CUDASeparateLibA + CUDASeparateLibB PROPERTIES POSITION_INDEPENDENT_CODE ON) diff --git a/Tests/Module/WriteCompilerDetectionHeader/main.cpp b/Tests/Module/WriteCompilerDetectionHeader/main.cpp index 192094c..9979cba 100644 --- a/Tests/Module/WriteCompilerDetectionHeader/main.cpp +++ b/Tests/Module/WriteCompilerDetectionHeader/main.cpp @@ -8,6 +8,9 @@ #error Expect no C features defined #endif +TEST_STATIC_ASSERT(true); +TEST_STATIC_ASSERT_MSG(true, "msg"); + int main() { return 0; diff --git a/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp b/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp index 1635091..d1f178f 100644 --- a/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp +++ b/Tests/Module/WriteCompilerDetectionHeader/multi_files.cpp @@ -8,6 +8,9 @@ #error Expect no C features defined #endif +MULTI_STATIC_ASSERT(true); +MULTI_STATIC_ASSERT_MSG(true, "msg"); + int main() { return 0; diff --git a/Tests/QtAutogen/CMakeLists.txt b/Tests/QtAutogen/CMakeLists.txt index 4960472..86af746 100644 --- a/Tests/QtAutogen/CMakeLists.txt +++ b/Tests/QtAutogen/CMakeLists.txt @@ -83,62 +83,92 @@ target_compile_features(empty PRIVATE ${QT_COMPILE_FEATURES}) # -- Test # When a file listed in a .qrc file changes the target must be rebuilt try_compile(RCC_DEPENDS - "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" - "${CMAKE_CURRENT_SOURCE_DIR}/autorcc_depends" - autorcc_depends + "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + "${CMAKE_CURRENT_SOURCE_DIR}/rccDepends" + rccDepends CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" OUTPUT_VARIABLE output ) if (NOT RCC_DEPENDS) - message(SEND_ERROR "Initial build of autorcc_depends failed. Output: ${output}") + message(SEND_ERROR "Initial build of rccDepends failed. Output: ${output}") endif() -file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/info_file.txt" qrc_files) - -list(GET qrc_files 0 qrc_file1) - +# Get name and timestamp of the output binary +file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/target1.txt" target1List) +list(GET target1List 0 binFile) set(timeformat "%Y%j%H%M%S") +file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") -file(TIMESTAMP "${qrc_file1}" file1_before "${timeformat}") - +# Touch first qrc input file and rebuild execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. -execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends/res1/input.txt") - +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/res1/input.txt") execute_process(COMMAND "${CMAKE_COMMAND}" --build . - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/autorcc_depends" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + RESULT_VARIABLE rccDepends_result ) +if (rccDepends_result) + message(SEND_ERROR "Second build of rccDepends failed.") +endif() +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${binFile}) should have changed in the first step!") +endif() -file(TIMESTAMP "${qrc_file1}" file1_step1 "${timeformat}") - -if (NOT file1_step1 GREATER file1_before) - message(SEND_ERROR "file1 (${qrc_file1}) should have changed in the first step!") +# Touch second qrc input file and rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) # Ensure that the timestamp will change. +execute_process(COMMAND "${CMAKE_COMMAND}" -E touch "${CMAKE_CURRENT_BINARY_DIR}/rccDepends/res2/input.txt") +execute_process(COMMAND "${CMAKE_COMMAND}" --build . + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/rccDepends" + RESULT_VARIABLE rccDepends_result +) +if (rccDepends_result) + message(SEND_ERROR "Third build of rccDepends failed.") +endif() +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep2 "${timeformat}") +if (NOT timeStep2 GREATER timeStep1) + message(SEND_ERROR "File (${binFile}) should have changed in the second step!") endif() # -- Test # Ensure a repeated build succeeds when a header containing a QObject changes try_compile(MOC_RERUN - "${CMAKE_CURRENT_BINARY_DIR}/automoc_rerun" - "${CMAKE_CURRENT_SOURCE_DIR}/automoc_rerun" - automoc_rerun + "${CMAKE_CURRENT_BINARY_DIR}/mocRerun" + "${CMAKE_CURRENT_SOURCE_DIR}/mocRerun" + mocRerun CMAKE_FLAGS "-DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}" "-DQT_TEST_VERSION=${QT_TEST_VERSION}" "-DCMAKE_PREFIX_PATH=${Qt_PREFIX_DIR}" OUTPUT_VARIABLE output ) if (NOT MOC_RERUN) - message(SEND_ERROR "Initial build of automoc_rerun failed. Output: ${output}") + message(SEND_ERROR "Initial build of mocRerun failed. Output: ${output}") endif() -configure_file(automoc_rerun/test1.h.in2 automoc_rerun/test1.h COPYONLY) +# Get name and timestamp of the output binary +file(STRINGS "${CMAKE_CURRENT_BINARY_DIR}/mocRerun/target1.txt" target1List) +list(GET target1List 0 binFile) +set(timeformat "%Y%j%H%M%S") +file(TIMESTAMP "${binFile}" timeBegin "${timeformat}") +# Change file content and rebuild +execute_process(COMMAND "${CMAKE_COMMAND}" -E sleep 1) +configure_file(mocRerun/test1b.h.in mocRerun/test1.h COPYONLY) execute_process(COMMAND "${CMAKE_COMMAND}" --build . - WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/automoc_rerun" - RESULT_VARIABLE automoc_rerun_result + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/mocRerun" + RESULT_VARIABLE mocRerun_result ) -if (automoc_rerun_result) - message(SEND_ERROR "Second build of automoc_rerun failed.") +if (mocRerun_result) + message(SEND_ERROR "Second build of mocRerun failed.") +endif() + +# Compare timestamps +file(TIMESTAMP "${binFile}" timeStep1 "${timeformat}") +if (NOT timeStep1 GREATER timeBegin) + message(SEND_ERROR "File (${binFile}) should have changed in the first step!") endif() # -- Test @@ -209,6 +239,10 @@ target_link_libraries(skipRccB ${QT_LIBRARIES}) add_subdirectory(sameName) # -- Test +# Tests AUTOMOC with generated sources +add_subdirectory(mocDepends) + +# -- Test # Tests various include moc patterns add_subdirectory(mocIncludeStrict) diff --git a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt b/Tests/QtAutogen/automoc_rerun/CMakeLists.txt deleted file mode 100644 index 92a682b..0000000 --- a/Tests/QtAutogen/automoc_rerun/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.7) -project(automoc_rerun CXX) - -if (QT_TEST_VERSION STREQUAL 4) - find_package(Qt4 REQUIRED) - set(QT_CORE_TARGET Qt4::QtCore) -else() - if (NOT QT_TEST_VERSION STREQUAL 5) - message(SEND_ERROR "Invalid Qt version specified.") - endif() - - find_package(Qt5Core REQUIRED) - set(QT_CORE_TARGET Qt5::Core) -endif() - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) - -configure_file(test1.h.in1 test1.h COPYONLY) - -add_executable(test1 - ${CMAKE_CURRENT_BINARY_DIR}/test1.h - test1.cpp - res1.qrc - ) -target_include_directories(test1 PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(test1 ${QT_CORE_TARGET}) diff --git a/Tests/QtAutogen/automoc_rerun/test1.cpp b/Tests/QtAutogen/automoc_rerun/test1.cpp deleted file mode 100644 index 4316a91..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "test1.h" -int main() -{ - return 0; -} diff --git a/Tests/QtAutogen/automoc_rerun/test1.h.in1 b/Tests/QtAutogen/automoc_rerun/test1.h.in1 deleted file mode 100644 index fee2c09..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.h.in1 +++ /dev/null @@ -1,8 +0,0 @@ -#include <QObject> -class test1 : public QObject -{ - Q_OBJECT - public slots: - void onTst1() {} - void onTst2() {} -}; diff --git a/Tests/QtAutogen/automoc_rerun/test1.h.in2 b/Tests/QtAutogen/automoc_rerun/test1.h.in2 deleted file mode 100644 index 6531d10..0000000 --- a/Tests/QtAutogen/automoc_rerun/test1.h.in2 +++ /dev/null @@ -1,7 +0,0 @@ -#include <QObject> -class test1 : public QObject -{ - Q_OBJECT - public slots: - void onTst1() {} -}; diff --git a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt b/Tests/QtAutogen/autorcc_depends/CMakeLists.txt deleted file mode 100644 index 7b51e11..0000000 --- a/Tests/QtAutogen/autorcc_depends/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.7) -project(autorcc_depends) - -set(CMAKE_AUTORCC ON) - -if (QT_TEST_VERSION STREQUAL 4) - find_package(Qt4 REQUIRED) - set(QT_CORE_TARGET Qt4::QtCore) -else() - if (NOT QT_TEST_VERSION STREQUAL 5) - message(SEND_ERROR "Invalid Qt version specified.") - endif() - - find_package(Qt5Core REQUIRED) - set(QT_CORE_TARGET Qt5::Core) -endif() - -configure_file(res1.qrc.in res1.qrc @ONLY) -configure_file(res1/input.txt.in res1/input.txt @ONLY) - -add_executable(test_res1 - test_res1.cpp - ${CMAKE_CURRENT_BINARY_DIR}/res1.qrc -) -target_link_libraries(test_res1 ${QT_CORE_TARGET}) -add_custom_command(TARGET test_res1 POST_BUILD COMMAND - ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:test_res1>" > info_file.txt) diff --git a/Tests/QtAutogen/mocDepends/CMakeLists.txt b/Tests/QtAutogen/mocDepends/CMakeLists.txt new file mode 100644 index 0000000..8bd72eb --- /dev/null +++ b/Tests/QtAutogen/mocDepends/CMakeLists.txt @@ -0,0 +1,45 @@ +cmake_minimum_required(VERSION 3.7) +project(mocDepends) + +if (QT_TEST_VERSION STREQUAL 4) + find_package(Qt4 REQUIRED) + set(QT_CORE_TARGET Qt4::QtCore) +else() + if (NOT QT_TEST_VERSION STREQUAL 5) + message(SEND_ERROR "Invalid Qt version specified.") + endif() + + find_package(Qt5Core REQUIRED) + set(QT_CORE_TARGET Qt5::Core) +endif() + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +# -- Test 1 using generated header +# This tests the dependency of AUTOMOC of mocDepends1 to the generated object.hpp +add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/object.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/object.hpp + ) + +add_executable(mocDepends1 test1.cpp + ${CMAKE_CURRENT_BINARY_DIR}/object.hpp +) +target_link_libraries(mocDepends1 ${QT_CORE_TARGET}) +set_target_properties(mocDepends1 PROPERTIES AUTOMOC TRUE) + +# -- Test 2 using generated library +# This tests the dependency of AUTOMOC of mocDepends2 to the +# generated simpleLib.hpp which belongs to a linked library of mocDepends2 +add_custom_command(OUTPUT simpleLib.hpp simpleLib.cpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/invalid.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.hpp + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/simpleLib.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/simpleLib.cpp + ) +add_library(SimpleLib STATIC simpleLib.hpp simpleLib.cpp) + +add_executable(mocDepends2 test2.cpp ) +target_link_libraries(mocDepends2 SimpleLib ${QT_CORE_TARGET}) +set_target_properties(mocDepends2 PROPERTIES AUTOMOC TRUE) diff --git a/Tests/QtAutogen/mocDepends/invalid.hpp.in b/Tests/QtAutogen/mocDepends/invalid.hpp.in new file mode 100644 index 0000000..854d9a1 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/invalid.hpp.in @@ -0,0 +1 @@ +#ifndef diff --git a/Tests/QtAutogen/mocDepends/object.hpp.in b/Tests/QtAutogen/mocDepends/object.hpp.in new file mode 100644 index 0000000..f364f7c --- /dev/null +++ b/Tests/QtAutogen/mocDepends/object.hpp.in @@ -0,0 +1,14 @@ +#ifndef OBJECT_HPP +#define OBJECT_HPP + +#include <QObject> + +class Object : public QObject +{ + Q_OBJECT +public: + Q_SLOT + void aSlot(){}; +}; + +#endif diff --git a/Tests/QtAutogen/mocDepends/simpleLib.cpp.in b/Tests/QtAutogen/mocDepends/simpleLib.cpp.in new file mode 100644 index 0000000..fa33bd3 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/simpleLib.cpp.in @@ -0,0 +1,9 @@ +#include "simpleLib.hpp" + +SimpleLib::SimpleLib() +{ +} + +SimpleLib::~SimpleLib() +{ +} diff --git a/Tests/QtAutogen/mocDepends/simpleLib.hpp.in b/Tests/QtAutogen/mocDepends/simpleLib.hpp.in new file mode 100644 index 0000000..758f1f6 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/simpleLib.hpp.in @@ -0,0 +1,11 @@ +#ifndef SIMPLE_LIB_H +#define SIMPLE_LIB_H + +class SimpleLib +{ +public: + SimpleLib(); + ~SimpleLib(); +}; + +#endif diff --git a/Tests/QtAutogen/mocDepends/test1.cpp b/Tests/QtAutogen/mocDepends/test1.cpp new file mode 100644 index 0000000..92c259c --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test1.cpp @@ -0,0 +1,9 @@ + +#include "object.hpp" + +int main() +{ + Object obj; + + return 0; +} diff --git a/Tests/QtAutogen/mocDepends/test2.cpp b/Tests/QtAutogen/mocDepends/test2.cpp new file mode 100644 index 0000000..155b19b --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test2.cpp @@ -0,0 +1,10 @@ + +#include "test2.hpp" + +int main() +{ + SimpleLib obj; + LObject lobject; + + return 0; +} diff --git a/Tests/QtAutogen/mocDepends/test2.hpp b/Tests/QtAutogen/mocDepends/test2.hpp new file mode 100644 index 0000000..0125f07 --- /dev/null +++ b/Tests/QtAutogen/mocDepends/test2.hpp @@ -0,0 +1,16 @@ +#ifndef TEST2_HPP +#define TEST2_HPP + +#include "simpleLib.hpp" +#include <QObject> + +// This object triggers the AUTOMOC on this file +class LObject : public QObject +{ + Q_OBJECT +public: + Q_SLOT + void aSlot(){}; +}; + +#endif diff --git a/Tests/QtAutogen/mocRerun/CMakeLists.txt b/Tests/QtAutogen/mocRerun/CMakeLists.txt new file mode 100644 index 0000000..6689f50 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/CMakeLists.txt @@ -0,0 +1,35 @@ +cmake_minimum_required(VERSION 3.7) +project(mocRerun CXX) + +if (QT_TEST_VERSION STREQUAL 4) + find_package(Qt4 REQUIRED) + set(QT_CORE_TARGET Qt4::QtCore) +else() + if (NOT QT_TEST_VERSION STREQUAL 5) + message(SEND_ERROR "Invalid Qt version specified.") + endif() + + find_package(Qt5Core REQUIRED) + set(QT_CORE_TARGET Qt5::Core) +endif() + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +configure_file(test1a.h.in test1.h COPYONLY) +# Generated source file +add_custom_command(OUTPUT main.cpp + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + ) + +add_executable(mocRerun + ${CMAKE_CURRENT_BINARY_DIR}/test1.h + ${CMAKE_CURRENT_BINARY_DIR}/main.cpp + res1.qrc + ) +target_include_directories(mocRerun PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) +target_link_libraries(mocRerun ${QT_CORE_TARGET}) +# Write target name to text file +add_custom_command(TARGET mocRerun POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:mocRerun>" > target1.txt) diff --git a/Tests/QtAutogen/automoc_rerun/input.txt b/Tests/QtAutogen/mocRerun/input.txt index da62762..da62762 100644 --- a/Tests/QtAutogen/automoc_rerun/input.txt +++ b/Tests/QtAutogen/mocRerun/input.txt diff --git a/Tests/QtAutogen/mocRerun/main.cpp.in b/Tests/QtAutogen/mocRerun/main.cpp.in new file mode 100644 index 0000000..b37ff61 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/main.cpp.in @@ -0,0 +1,18 @@ +#include "test1.h" + +class Test2 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} +}; + +int main() +{ + Test1 test1; + Test2 test2; + + return 0; +} + +#include "main.moc" diff --git a/Tests/QtAutogen/automoc_rerun/res1.qrc b/Tests/QtAutogen/mocRerun/res1.qrc index fb804b5..fb804b5 100644 --- a/Tests/QtAutogen/automoc_rerun/res1.qrc +++ b/Tests/QtAutogen/mocRerun/res1.qrc diff --git a/Tests/QtAutogen/mocRerun/test1a.h.in b/Tests/QtAutogen/mocRerun/test1a.h.in new file mode 100644 index 0000000..a335046 --- /dev/null +++ b/Tests/QtAutogen/mocRerun/test1a.h.in @@ -0,0 +1,8 @@ +#include <QObject> +class Test1 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} + void onTst2() {} +}; diff --git a/Tests/QtAutogen/mocRerun/test1b.h.in b/Tests/QtAutogen/mocRerun/test1b.h.in new file mode 100644 index 0000000..6128eeb --- /dev/null +++ b/Tests/QtAutogen/mocRerun/test1b.h.in @@ -0,0 +1,7 @@ +#include <QObject> +class Test1 : public QObject +{ + Q_OBJECT +public slots: + void onTst1() {} +}; diff --git a/Tests/QtAutogen/rccDepends/CMakeLists.txt b/Tests/QtAutogen/rccDepends/CMakeLists.txt new file mode 100644 index 0000000..de98573 --- /dev/null +++ b/Tests/QtAutogen/rccDepends/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 3.7) +project(rccDepends) + +set(CMAKE_AUTORCC ON) + +if (QT_TEST_VERSION STREQUAL 4) + find_package(Qt4 REQUIRED) + set(QT_CORE_TARGET Qt4::QtCore) +else() + if (NOT QT_TEST_VERSION STREQUAL 5) + message(SEND_ERROR "Invalid Qt version specified.") + endif() + + find_package(Qt5Core REQUIRED) + set(QT_CORE_TARGET Qt5::Core) +endif() + +configure_file(res/input1.txt.in res1/input.txt @ONLY) +configure_file(res/input2.txt.in res2/input.txt @ONLY) +# Configure time generated qrc file +configure_file(res1.qrc.in res1.qrc @ONLY) +# Dependency generated qrc file +add_custom_command(OUTPUT res2.qrc + COMMAND ${CMAKE_COMMAND} -E sleep 3 + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/res2.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc + ) + + +add_executable(rccDepends + main.cpp + ${CMAKE_CURRENT_BINARY_DIR}/res1.qrc + ${CMAKE_CURRENT_BINARY_DIR}/res2.qrc +) +target_link_libraries(rccDepends ${QT_CORE_TARGET}) +add_custom_command(TARGET rccDepends POST_BUILD COMMAND + ${CMAKE_COMMAND} -E echo "$<TARGET_FILE:rccDepends>" > target1.txt) diff --git a/Tests/QtAutogen/autorcc_depends/test_res1.cpp b/Tests/QtAutogen/rccDepends/main.cpp index 766b775..766b775 100644 --- a/Tests/QtAutogen/autorcc_depends/test_res1.cpp +++ b/Tests/QtAutogen/rccDepends/main.cpp diff --git a/Tests/QtAutogen/autorcc_depends/res1/input.txt.in b/Tests/QtAutogen/rccDepends/res/input1.txt.in index da62762..da62762 100644 --- a/Tests/QtAutogen/autorcc_depends/res1/input.txt.in +++ b/Tests/QtAutogen/rccDepends/res/input1.txt.in diff --git a/Tests/QtAutogen/rccDepends/res/input2.txt.in b/Tests/QtAutogen/rccDepends/res/input2.txt.in new file mode 100644 index 0000000..08e14b7 --- /dev/null +++ b/Tests/QtAutogen/rccDepends/res/input2.txt.in @@ -0,0 +1 @@ +Res2 input. diff --git a/Tests/QtAutogen/autorcc_depends/res1.qrc.in b/Tests/QtAutogen/rccDepends/res1.qrc.in index 2a5417b..2a5417b 100644 --- a/Tests/QtAutogen/autorcc_depends/res1.qrc.in +++ b/Tests/QtAutogen/rccDepends/res1.qrc.in diff --git a/Tests/QtAutogen/rccDepends/res2.qrc.in b/Tests/QtAutogen/rccDepends/res2.qrc.in new file mode 100644 index 0000000..18b916a --- /dev/null +++ b/Tests/QtAutogen/rccDepends/res2.qrc.in @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/"> + <file>res2/input.txt</file> + </qresource> +</RCC> diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index 6423bfd..5157b9f 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -156,6 +156,9 @@ add_RunCMake_test(TargetPropertyGeneratorExpressions) add_RunCMake_test(Languages) add_RunCMake_test(LinkStatic) add_RunCMake_test(ObjectLibrary) +if(UNIX AND CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG AND CMAKE_EXECUTABLE_FORMAT STREQUAL "ELF") + add_RunCMake_test(RuntimePath) +endif() add_RunCMake_test(Swift) add_RunCMake_test(TargetObjects) add_RunCMake_test(TargetSources) diff --git a/Tests/RunCMake/RuntimePath/A.c b/Tests/RunCMake/RuntimePath/A.c new file mode 100644 index 0000000..e9d4195 --- /dev/null +++ b/Tests/RunCMake/RuntimePath/A.c @@ -0,0 +1,4 @@ +int libA(void) +{ + return 0; +} diff --git a/Tests/RunCMake/RuntimePath/CMakeLists.txt b/Tests/RunCMake/RuntimePath/CMakeLists.txt new file mode 100644 index 0000000..a640c56 --- /dev/null +++ b/Tests/RunCMake/RuntimePath/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 3.7) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake new file mode 100644 index 0000000..a9a7f05 --- /dev/null +++ b/Tests/RunCMake/RuntimePath/RunCMakeTest.cmake @@ -0,0 +1,18 @@ +include(RunCMake) + + +function(run_SymlinkImplicit) + # Use a single build tree for a few tests without cleaning. + set(RunCMake_TEST_BINARY_DIR ${RunCMake_BINARY_DIR}/SymlinkImplicit-build) + set(RunCMake_TEST_NO_CLEAN 1) + if(RunCMake_GENERATOR MATCHES "Make|Ninja") + set(RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug) + endif() + file(REMOVE_RECURSE "${RunCMake_TEST_BINARY_DIR}") + file(MAKE_DIRECTORY "${RunCMake_TEST_BINARY_DIR}") + run_cmake(SymlinkImplicit) + run_cmake_command(SymlinkImplicit-build ${CMAKE_COMMAND} --build . --config Debug) + run_cmake_command(SymlinkImplicitCheck + ${CMAKE_COMMAND} -Ddir=${RunCMake_TEST_BINARY_DIR} -P ${RunCMake_SOURCE_DIR}/SymlinkImplicitCheck.cmake) +endfunction() +run_SymlinkImplicit() diff --git a/Tests/RunCMake/RuntimePath/SymlinkImplicit.cmake b/Tests/RunCMake/RuntimePath/SymlinkImplicit.cmake new file mode 100644 index 0000000..6578f8f --- /dev/null +++ b/Tests/RunCMake/RuntimePath/SymlinkImplicit.cmake @@ -0,0 +1,17 @@ +enable_language(C) + +set(lib_dir ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(lib_link ${CMAKE_CURRENT_BINARY_DIR}/libLink) +set(lib_always ${CMAKE_CURRENT_BINARY_DIR}/libAlways) +file(MAKE_DIRECTORY ${lib_dir}) +execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink lib ${lib_link}) +execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink lib ${lib_always}) + +add_library(A SHARED A.c) +list(APPEND CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${lib_dir}) +set_property(TARGET A PROPERTY LIBRARY_OUTPUT_DIRECTORY ${lib_link}) + +add_executable(exe main.c) +target_link_libraries(exe A) +set_property(TARGET exe PROPERTY RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +set_property(TARGET exe PROPERTY BUILD_RPATH ${lib_always}) diff --git a/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-result.txt b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-stderr.txt b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-stderr.txt new file mode 100644 index 0000000..b0ede70 --- /dev/null +++ b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck-stderr.txt @@ -0,0 +1,22 @@ +^CMake Error at .*/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake:[0-9]+ \(file\): + file RPATH_CHANGE could not write new RPATH: + + old-should-not-exist + + to the file: + + [^ +]*/Tests/RunCMake/RuntimePath/SymlinkImplicit-build/exe + + The current (RPATH|RUNPATH) is: + + [^ +]*/Tests/RunCMake/RuntimePath/SymlinkImplicit-build/libAlways(:[^ +]*)? + + which does not contain: + + [^ +]*/Tests/RunCMake/RuntimePath/SymlinkImplicit-build/libLink + + as was expected\.$ diff --git a/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake new file mode 100644 index 0000000..d34742e --- /dev/null +++ b/Tests/RunCMake/RuntimePath/SymlinkImplicitCheck.cmake @@ -0,0 +1,2 @@ +file(COPY ${dir}/bin/exe DESTINATION ${dir}) +file(RPATH_CHANGE FILE "${dir}/exe" OLD_RPATH "${dir}/libLink" NEW_RPATH "old-should-not-exist") diff --git a/Tests/RunCMake/RuntimePath/main.c b/Tests/RunCMake/RuntimePath/main.c new file mode 100644 index 0000000..8488f4e --- /dev/null +++ b/Tests/RunCMake/RuntimePath/main.c @@ -0,0 +1,4 @@ +int main(void) +{ + return 0; +} diff --git a/Utilities/GitSetup/config b/Utilities/GitSetup/config index d69a679..2b4f037 100644 --- a/Utilities/GitSetup/config +++ b/Utilities/GitSetup/config @@ -1,9 +1,2 @@ [hooks] - url = https://cmake.org/cmake.git -[ssh] - host = cmake.org - key = id_git_cmake - request-url = https://www.kitware.com/Admin/SendPassword.cgi -[stage] - url = git://cmake.org/stage/cmake.git - pushurl = git@cmake.org:stage/cmake.git + url = https://gitlab.kitware.com/utils/gitsetup.git diff --git a/Utilities/Release/release_cmake.cmake b/Utilities/Release/release_cmake.cmake index 0db89b5..ee1a0dc 100644 --- a/Utilities/Release/release_cmake.cmake +++ b/Utilities/Release/release_cmake.cmake @@ -32,9 +32,15 @@ if(NOT DEFINED GIT_COMMAND) set(GIT_COMMAND git) endif() -if(${CMAKE_CREATE_VERSION} MATCHES "^(release|maint|next|nightly)$") +if(CMAKE_CREATE_VERSION MATCHES "^(master|release)$") + set(GIT_FETCH "") set(GIT_BRANCH origin/${CMAKE_CREATE_VERSION}) +elseif(CMAKE_CREATE_VERSION STREQUAL "nightly") + set(nightly stage/master/nightly/latest) + set(GIT_FETCH "${GIT_COMMAND} fetch origin refs/${nightly}:refs/remotes/origin/${nightly}") + set(GIT_BRANCH origin/${nightly}) else() + set(GIT_FETCH "") set(GIT_BRANCH ${CMAKE_CREATE_VERSION}) endif() diff --git a/Utilities/Release/release_cmake.sh.in b/Utilities/Release/release_cmake.sh.in index 1465129..f363b3d 100755 --- a/Utilities/Release/release_cmake.sh.in +++ b/Utilities/Release/release_cmake.sh.in @@ -94,13 +94,15 @@ cd @CMAKE_RELEASE_DIRECTORY@ if [ ! -z "@GIT_COMMAND@" ]; then # clone the repo without creating any source files in the directory # matching the branch being built (i.e. master CMake-2-8, etc) - @GIT_COMMAND@ clone -n git://cmake.org/cmake.git @CMAKE_CREATE_VERSION@ - check_exit_value $? "Checkout git cmake source" || exit 1 + @GIT_COMMAND@ clone -n https://gitlab.kitware.com/cmake/cmake.git @CMAKE_CREATE_VERSION@ + check_exit_value $? "git clone cmake source" || exit 1 # go into the git directory cd @CMAKE_CREATE_VERSION@ # run any extra commands if they exist @GIT_EXTRA@ check_exit_value $? "git extra cmake source" || exit 1 + @GIT_FETCH@ + check_exit_value $? "git extra fetch" || exit 1 # now checkout a copy on the local branch working @GIT_COMMAND@ checkout -b working @GIT_BRANCH@ check_exit_value $? "git checkout" || exit 1 diff --git a/Utilities/SetupForDevelopment.sh b/Utilities/SetupForDevelopment.sh index 39152bc..ff64a84 100755 --- a/Utilities/SetupForDevelopment.sh +++ b/Utilities/SetupForDevelopment.sh @@ -3,9 +3,6 @@ cd "${BASH_SOURCE%/*}/.." && Utilities/GitSetup/setup-user && echo && Utilities/GitSetup/setup-hooks && echo && -Utilities/GitSetup/setup-stage && echo && -(Utilities/GitSetup/setup-ssh || - echo 'Failed to setup SSH. Run this again to retry.') && echo && Utilities/GitSetup/tips # Rebase master by default @@ -13,5 +10,5 @@ git config rebase.stat true git config branch.master.rebase true # Record the version of this setup so Git/pre-commit can check it. -SetupForDevelopment_VERSION=1 +SetupForDevelopment_VERSION=2 git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION} diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in index 9581458..e3afc78 100644 --- a/Utilities/Sphinx/conf.py.in +++ b/Utilities/Sphinx/conf.py.in @@ -18,7 +18,9 @@ release = '@conf_release@' # full version string primary_domain = 'cmake' -exclude_patterns = [] +exclude_patterns = [ + 'dev', # ignore developer-only documentation + ] extensions = ['cmake'] templates_path = ['@conf_path@/templates'] @@ -404,6 +404,7 @@ CMAKE_CXX_SOURCES="\ cmUnsetCommand \ cmVersion \ cmWhileCommand \ + cmWorkingDirectory \ cmake \ cmakemain \ cmcmd \ |