Merge topic 'feature/include_guard'

c96f43b7 include_guard: add tests for the feature
80f1221f include_guard: add doc pages and a release note
85b52a04 include_guard: add vim syntax highlighting rules
d44bd1c2 include_guard: implement new command

Acked-by: Kitware Robot <kwrobot@kitware.com>
Reviewed-by: Craig Scott <craig.scott@crascit.com>
Merge-request: !928
This commit is contained in:
Brad King
2017-06-28 12:53:21 +00:00
committed by Kitware Robot
28 changed files with 336 additions and 1 deletions
+5 -1
View File
@@ -203,6 +203,9 @@ syn keyword cmakeKWinclude_directories contained
syn keyword cmakeKWinclude_external_msproject contained
\ GUID MAP_IMPORTED_CONFIG_ PLATFORM TYPE WIX
syn keyword cmakeKWinclude_guard contained
\ DIRECTORY GLOBAL
syn keyword cmakeKWinstall contained
\ ARCHIVE BUNDLE CODE COMPONENT CONFIGURATIONS CVS DESTDIR DESTINATION DIRECTORY DIRECTORY_PERMISSIONS DLL EXCLUDE_FROM_ALL EXPORT EXPORT_ANDROID_MK EXPORT_LINK_INTERFACE_LIBRARIES FILES FILES_MATCHING FILE_PERMISSIONS FRAMEWORK GROUP_EXECUTE GROUP_READ GROUP_WRITE IMPORTED_ INCLUDES INSTALL_PREFIX INTERFACE_INCLUDE_DIRECTORIES LIBRARY MACOSX_BUNDLE MESSAGE_NEVER NAMELINK_ONLY NAMELINK_SKIP NAMESPACE NDK OBJECTS OPTIONAL OWNER_EXECUTE OWNER_READ OWNER_WRITE PATTERN PERMISSIONS POST_INSTALL_SCRIPT PRE_INSTALL_SCRIPT PRIVATE_HEADER PROGRAMS PUBLIC_HEADER REGEX RENAME RESOURCE RUNTIME SCRIPT SETGID SETUID SOVERSION TARGETS TRUE USE_SOURCE_PERMISSIONS VERSION WORLD_EXECUTE WORLD_READ WORLD_WRITE
@@ -327,7 +330,7 @@ syn keyword cmakeGeneratorExpressions contained
syn case ignore
syn keyword cmakeCommand
\ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property enable_language enable_testing endfunction endmacro execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property include include_directories include_external_msproject include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch
\ add_compile_options add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_host_system_information cmake_minimum_required cmake_parse_arguments cmake_policy configure_file continue create_test_sourcelist ctest_build ctest_configure ctest_coverage ctest_empty_binary_directory ctest_memcheck ctest_read_custom_files ctest_run_script ctest_sleep ctest_start ctest_submit ctest_test ctest_update ctest_upload define_property enable_language enable_testing endfunction endmacro execute_process export file find_file find_library find_package find_path find_program fltk_wrap_ui function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property include include_directories include_external_msproject include_guard include_regular_expression install link_directories list load_cache load_command macro mark_as_advanced math message option project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_compile_definitions target_compile_features target_compile_options target_include_directories target_link_libraries target_sources try_compile try_run unset variable_watch
\ nextgroup=cmakeArguments
syn keyword cmakeCommandConditional
@@ -420,6 +423,7 @@ hi def link cmakeKWif ModeMsg
hi def link cmakeKWinclude ModeMsg
hi def link cmakeKWinclude_directories ModeMsg
hi def link cmakeKWinclude_external_msproject ModeMsg
hi def link cmakeKWinclude_guard ModeMsg
hi def link cmakeKWinstall ModeMsg
hi def link cmakeKWinstall_files ModeMsg
hi def link cmakeKWinstall_programs ModeMsg
+46
View File
@@ -0,0 +1,46 @@
include_guard
-------------
Provides an include guard for the file currently being processed by CMake.
::
include_guard([DIRECTORY|GLOBAL])
Sets up an include guard for the current CMake file (see the
:variable:`CMAKE_CURRENT_LIST_FILE` variable documentation).
CMake will end its processing of the current file at the location of the
:command:`include_guard` command if the current file has already been
processed for the applicable scope (see below). This provides functionality
similar to the include guards commonly used in source headers or to the
``#pragma once`` directive. If the current file has been processed previously
for the applicable scope, the effect is as though :command:`return` had been
called. Do not call this command from inside a function being defined within
the current file.
An optional argument specifying the scope of the guard may be provided.
Possible values for the option are:
``DIRECTORY``
The include guard applies within the current directory and below. The file
will only be included once within this directory scope, but may be included
again by other files outside of this directory (i.e. a parent directory or
another directory not pulled in by :command:`add_subdirectory` or
:command:`include` from the current file or its children).
``GLOBAL``
The include guard applies globally to the whole build. The current file
will only be included once regardless of the scope.
If no arguments given, ``include_guard`` has the same scope as a variable,
meaning that the include guard effect is isolated by the most recent
function scope or current directory if no inner function scopes exist.
In this case the command behavior is the same as:
.. code-block:: cmake
if(__CURRENT_FILE_VAR__)
return()
endif()
set(__CURRENT_FILE_VAR__ TRUE)
+1
View File
@@ -44,6 +44,7 @@ These commands are always available.
/command/get_property
/command/if
/command/include
/command/include_guard
/command/list
/command/macro
/command/mark_as_advanced
+8
View File
@@ -0,0 +1,8 @@
include_guard
-------------
* The :command:`include_guard` command was introduced to allow guarding
CMake scripts from being included more than once. The command supports
``DIRECTORY`` and ``GLOBAL`` options to adjust the corresponding include guard
scope. If no options given, include guard is similar to basic variable-based
check.
+2
View File
@@ -469,6 +469,8 @@ set(SRCS
cmIncludeDirectoryCommand.h
cmIncludeExternalMSProjectCommand.cxx
cmIncludeExternalMSProjectCommand.h
cmIncludeGuardCommand.cxx
cmIncludeGuardCommand.h
cmIncludeRegularExpressionCommand.cxx
cmIncludeRegularExpressionCommand.h
cmInstallCommand.cxx
+2
View File
@@ -42,6 +42,7 @@
#include "cmIfCommand.h"
#include "cmIncludeCommand.h"
#include "cmIncludeDirectoryCommand.h"
#include "cmIncludeGuardCommand.h"
#include "cmIncludeRegularExpressionCommand.h"
#include "cmInstallCommand.h"
#include "cmInstallFilesCommand.h"
@@ -132,6 +133,7 @@ void GetScriptingCommands(cmState* state)
state->AddBuiltinCommand("get_property", new cmGetPropertyCommand);
state->AddBuiltinCommand("if", new cmIfCommand);
state->AddBuiltinCommand("include", new cmIncludeCommand);
state->AddBuiltinCommand("include_guard", new cmIncludeGuardCommand);
state->AddBuiltinCommand("list", new cmListCommand);
state->AddBuiltinCommand("macro", new cmMacroCommand);
state->AddBuiltinCommand("make_directory", new cmMakeDirectoryCommand);
+108
View File
@@ -0,0 +1,108 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#include "cmIncludeGuardCommand.h"
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmStateDirectory.h"
#include "cmStateSnapshot.h"
#include "cmSystemTools.h"
#include "cmake.h"
namespace {
enum IncludeGuardScope
{
VARIABLE,
DIRECTORY,
GLOBAL
};
std::string GetIncludeGuardVariableName(std::string const& filePath)
{
std::string result = "__INCGUARD_";
#ifdef CMAKE_BUILD_WITH_CMAKE
result += cmSystemTools::ComputeStringMD5(filePath);
#else
result += cmSystemTools::MakeCidentifier(filePath);
#endif
result += "__";
return result;
}
bool CheckIncludeGuardIsSet(cmMakefile* mf, std::string const& includeGuardVar)
{
if (mf->GetProperty(includeGuardVar)) {
return true;
}
cmStateSnapshot dirSnapshot =
mf->GetStateSnapshot().GetBuildsystemDirectoryParent();
while (dirSnapshot.GetState()) {
cmStateDirectory stateDir = dirSnapshot.GetDirectory();
if (stateDir.GetProperty(includeGuardVar)) {
return true;
}
dirSnapshot = dirSnapshot.GetBuildsystemDirectoryParent();
}
return false;
}
} // anonymous namespace
// cmIncludeGuardCommand
bool cmIncludeGuardCommand::InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status)
{
if (args.size() > 1) {
this->SetError(
"given an invalid number of arguments. The command takes at "
"most 1 argument.");
return false;
}
IncludeGuardScope scope = VARIABLE;
if (!args.empty()) {
std::string const& arg = args[0];
if (arg == "DIRECTORY") {
scope = DIRECTORY;
} else if (arg == "GLOBAL") {
scope = GLOBAL;
} else {
this->SetError("given an invalid scope: " + arg);
return false;
}
}
std::string includeGuardVar = GetIncludeGuardVariableName(
this->Makefile->GetDefinition("CMAKE_CURRENT_LIST_FILE"));
cmMakefile* const mf = this->Makefile;
switch (scope) {
case VARIABLE:
if (mf->IsDefinitionSet(includeGuardVar)) {
status.SetReturnInvoked();
return true;
}
mf->AddDefinition(includeGuardVar, true);
break;
case DIRECTORY:
if (CheckIncludeGuardIsSet(mf, includeGuardVar)) {
status.SetReturnInvoked();
return true;
}
mf->SetProperty(includeGuardVar, "TRUE");
break;
case GLOBAL:
cmake* const cm = mf->GetCMakeInstance();
if (cm->GetProperty(includeGuardVar)) {
status.SetReturnInvoked();
return true;
}
cm->SetProperty(includeGuardVar, "TRUE");
break;
}
return true;
}
+37
View File
@@ -0,0 +1,37 @@
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
file Copyright.txt or https://cmake.org/licensing for details. */
#ifndef cmIncludeGuardCommand_h
#define cmIncludeGuardCommand_h
#include "cmConfigure.h"
#include <string>
#include <vector>
#include "cmCommand.h"
class cmExecutionStatus;
/** \class cmIncludeGuardCommand
* \brief cmIncludeGuardCommand identical to C++ #pragma_once command
* Can work in 3 modes: GLOBAL (works on global properties),
* DIRECTORY(use directory property), VARIABLE(unnamed overload without
* arguments) define an ordinary variable to be used as include guard checker
*/
class cmIncludeGuardCommand : public cmCommand
{
public:
/**
* This is a virtual constructor for the command.
*/
cmCommand* Clone() CM_OVERRIDE { return new cmIncludeGuardCommand; }
/**
* This is called when the command is first encountered in
* the CMakeLists.txt file.
*/
bool InitialPass(std::vector<std::string> const& args,
cmExecutionStatus& status) CM_OVERRIDE;
};
#endif
+1
View File
@@ -215,6 +215,7 @@ add_RunCMake_test(get_property)
add_RunCMake_test(if)
add_RunCMake_test(include)
add_RunCMake_test(include_directories)
add_RunCMake_test(include_guard)
add_RunCMake_test(list)
add_RunCMake_test(message)
add_RunCMake_test(project -DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES})
@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.9)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
@@ -0,0 +1,19 @@
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Scripts")
# Test include_guard with DIRECTORY scope
# Add subdirectory which includes DirScript three times:
# 1. Include at inner function scope
# 2. At directory scope
# 3. At another subdirectory to check that the guard is checked
# against parent directories
add_subdirectory(sub_dir_script1)
# Add another directory which includes DirScript
add_subdirectory(sub_dir_script2)
# check inclusions count
get_property(dir_count GLOBAL PROPERTY DIR_SCRIPT_COUNT)
if(NOT dir_count EQUAL 2)
message(FATAL_ERROR
"Wrong DIR_SCRIPT_COUNT value: ${dir_count}, expected: 2")
endif()
@@ -0,0 +1,11 @@
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Scripts")
# Test GLOBAL include guard
add_subdirectory(global_script_dir)
include(GlobScript)
get_property(glob_count GLOBAL PROPERTY GLOB_SCRIPT_COUNT)
if(NOT glob_count EQUAL 1)
message(FATAL_ERROR
"Wrong GLOB_SCRIPT_COUNT value: ${glob_count}, expected: 1")
endif()
@@ -0,0 +1 @@
1
@@ -0,0 +1,5 @@
CMake Error at InvalidArgumentsNumber.cmake:1 \(include_guard\):
include_guard given an invalid number of arguments. The command takes at
most 1 argument.
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
@@ -0,0 +1 @@
include_guard(ARG1 ARG2)
@@ -0,0 +1 @@
1
@@ -0,0 +1,4 @@
CMake Error at InvalidScope.cmake:1 \(include_guard\):
include_guard given an invalid scope: INVALID
Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)
@@ -0,0 +1 @@
include_guard(INVALID)
@@ -0,0 +1,7 @@
include(RunCMake)
run_cmake(VariableScope)
run_cmake(DirectoryScope)
run_cmake(GlobalScope)
run_cmake(InvalidScope)
run_cmake(InvalidArgumentsNumber)
@@ -0,0 +1,12 @@
include_guard(DIRECTORY)
set(prop_name DIR_SCRIPT_COUNT)
get_property(count_is_set GLOBAL PROPERTY ${prop_name} SET)
if(NOT count_is_set)
set_property(GLOBAL PROPERTY ${prop_name} 1)
else()
get_property(count GLOBAL PROPERTY ${prop_name})
math(EXPR count "${count} + 1")
set_property(GLOBAL PROPERTY ${prop_name} ${count})
endif()
@@ -0,0 +1,12 @@
include_guard(GLOBAL)
set(prop_name GLOB_SCRIPT_COUNT)
get_property(count_is_set GLOBAL PROPERTY ${prop_name} SET)
if(NOT count_is_set)
set_property(GLOBAL PROPERTY ${prop_name} 1)
else()
get_property(count GLOBAL PROPERTY ${prop_name})
math(EXPR count "${count} + 1")
set_property(GLOBAL PROPERTY ${prop_name} ${count})
endif()
@@ -0,0 +1,12 @@
include_guard()
set(prop_name VAR_SCRIPT_COUNT)
get_property(count_is_set GLOBAL PROPERTY ${prop_name} SET)
if(NOT count_is_set)
set_property(GLOBAL PROPERTY ${prop_name} 1)
else()
get_property(count GLOBAL PROPERTY ${prop_name})
math(EXPR count "${count} + 1")
set_property(GLOBAL PROPERTY ${prop_name} ${count})
endif()
@@ -0,0 +1,24 @@
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/Scripts")
# Test include_guard with VARIABLE scope
function(var_include_func)
# Include twice in the same scope
include(VarScript)
include(VarScript)
get_property(var_count GLOBAL PROPERTY VAR_SCRIPT_COUNT)
if(NOT var_count EQUAL 1)
message(FATAL_ERROR
"Wrong VAR_SCRIPT_COUNT value: ${var_count}, expected: 1")
endif()
endfunction()
var_include_func()
# Check again that include_guard has been reset
include(VarScript)
get_property(var_count GLOBAL PROPERTY VAR_SCRIPT_COUNT)
if(NOT var_count EQUAL 2)
message(FATAL_ERROR
"Wrong VAR_SCRIPT_COUNT value: ${var_count}, expected: 2")
endif()
@@ -0,0 +1 @@
include(GlobScript)
@@ -0,0 +1,9 @@
function(dir_check)
include(DirScript)
endfunction()
dir_check()
include(DirScript)
add_subdirectory(sub_dir_script3)
@@ -0,0 +1 @@
include(DirScript)
@@ -0,0 +1 @@
include(DirScript)
+1
View File
@@ -330,6 +330,7 @@ CMAKE_CXX_SOURCES="\
cmHexFileConverter \
cmIfCommand \
cmIncludeCommand \
cmIncludeGuardCommand \
cmIncludeDirectoryCommand \
cmIncludeRegularExpressionCommand \
cmInstallCommand \