ign-cmake-ignition-cmake2_2.10.0/0000775000175000017500000000000014160533245016414 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/cmake/0000775000175000017500000000000014160533245017474 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/cmake/FindTINYXML2.cmake0000664000175000017500000000351214160533245022526 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find tinyxml2. Only debian distributions package tinyxml with a pkg-config. include(IgnPkgConfig) # Use pkg_check_modules to start ign_pkg_check_modules_quiet(TINYXML2 tinyxml2) # If that failed, then fall back to manual detection (necessary for MacOS) if(NOT TINYXML2_FOUND) if(NOT TINYXML2_FIND_QUIETLY) message(STATUS "Attempting manual search for tinyxml2") endif() find_path(TINYXML2_INCLUDE_DIRS tinyxml2.h ${TINYXML2_INCLUDE_DIRS} ENV CPATH) find_library(TINYXML2_LIBRARIES NAMES tinyxml2) set(TINYXML2_FOUND true) if(NOT TINYXML2_INCLUDE_DIRS) if(NOT TINYXML2_FIND_QUIETLY) message(STATUS "Looking for tinyxml2 headers - not found") endif() set(TINYXML2_FOUND false) endif() if(NOT TINYXML2_LIBRARIES) if(NOT TINYXML2_FIND_QUIETLY) message (STATUS "Looking for tinyxml2 library - not found") endif() set(TINYXML2_FOUND false) endif() if(TINYXML2_FOUND) include(IgnImportTarget) ign_import_target(TINYXML2) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( TINYXML2 REQUIRED_VARS TINYXML2_FOUND) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/pkgconfig/0000775000175000017500000000000014160533245021443 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/cmake/pkgconfig/ignition.pc.in0000664000175000017500000000120114160533245024206 0ustar jriverojriveroprefix=${pcfiledir}/@PC_CONFIG_RELATIVE_PATH_TO_PREFIX@ libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@IGN_INCLUDE_INSTALL_DIR_POSTFIX@ Name: Ignition @IGN_DESIGNATION@ Description: A set of @IGN_DESIGNATION@ classes for robot applications Version: @PROJECT_VERSION_FULL_NO_SUFFIX@ Requires: ignition-cmake@IGNITION_CMAKE_VERSION_MAJOR@ >= 1.1 @PROJECT_PKGCONFIG_REQUIRES@ Requires.private: @PROJECT_PKGCONFIG_REQUIRES_PRIVATE@ Libs: -L${libdir} @project_pkgconfig_core_lib@ @PROJECT_PKGCONFIG_LIBS@ Libs.private: @PROJECT_PKGCONFIG_LIBS_PRIVATE@ CFlags: -I${includedir} @PROJECT_PKGCONFIG_CFLAGS@ ign-cmake-ignition-cmake2_2.10.0/cmake/pkgconfig/ignition-component.pc.in0000664000175000017500000000126214160533245026215 0ustar jriverojriveroprefix=${pcfiledir}/@PC_CONFIG_RELATIVE_PATH_TO_PREFIX@ libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/@IGN_INCLUDE_INSTALL_DIR_POSTFIX@ Name: Ignition @IGN_DESIGNATION@ @component_name@ Description: A set of @IGN_DESIGNATION@ @component_name@ classes for robot applications Version: ignition-cmake@IGNITION_CMAKE_VERSION_MAJOR@ >= 1.1 @PROJECT_VERSION_FULL_NO_SUFFIX@ Requires: @component_pkgconfig_requires@ Requires.private: @component_pkgconfig_requires_private@ Libs: -L${libdir} @component_pkgconfig_lib@ @component_pkgconfig_lib_deps@ Libs.private: @component_pkgconfig_lib_deps_private@ CFLags: -I${includedir} @component_pkgconfig_cflags@ ign-cmake-ignition-cmake2_2.10.0/cmake/version_info.json.in0000664000175000017500000000233014160533245023472 0ustar jriverojrivero{ "build": { "cmake_build_type": "${CMAKE_BUILD_TYPE}", "build_time": "${build_time}", "platform": { "hostname": "${HOST}", "fqdn": "${FQDN}", "memory": { "total_virtual": "${TOTAL_VIRTUAL}", "available_virtual": "${AVAILABLE_VIRTUAL}", "total_physical": "${TOTAL_PHYSICAL}", "available_physical": "${AVAILABLE_PHYSICAL}" }, "processor": { "name": "${PROC_NAME}", "description": "${PROC_DESC}", "serial_number": "${PROC_SERIAL}", "number_of_logical_cores": "${NUM_LOGICAL}", "number_of_physical_cores": "${NUM_PHYSICAL}" }, "os": { "name": "${OS_NAME}", "release": "${OS_RELEASE}", "version": "${OS_VERSION}", "platform": "${OS_PLATFORM}" } } }, "hg": { "hash": "${HG_GLOBAL_REVISION}", "revision_number": "${HG_REVISION_NUM}", "branch": "${HG_BRANCH}" }, "ignition": { "project_name": "${PROJECT_NAME}", "version": "${PROJECT_VERSION}", "version_full": "${PROJECT_VERSION_FULL}", "major": "${PROJECT_VERSION_MAJOR}", "minor": "${PROJECT_VERSION_MINOR}", "patch": "${PROJECT_VERSION_PATCH}" } } ign-cmake-ignition-cmake2_2.10.0/cmake/FindIFADDRS.cmake0000664000175000017500000000236114160533245022355 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find ifaddrs # If we cannot find the header or the library, we will switch this to false set(IFADDRS_FOUND true) # Find ifaddrs.h find_path(IFADDRS_INCLUDE_DIRS ifaddrs.h) if(NOT IFADDRS_INCLUDE_DIRS) set(IFADDRS_FOUND false) endif() if(IFADDRS_FOUND) include(IgnImportTarget) # Since this is a header-only library, we should import it as an INTERFACE # target. ign_import_target(IFADDRS INTERFACE) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( IFADDRS REQUIRED_VARS IFADDRS_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/IgnCreateDocs.cmake0000664000175000017500000002030014160533245023143 0ustar jriverojrivero#.rst # IgnCreatePackage # ---------------- # # ign_create_docs # # Creates documentation for an ignition library project. # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################# # ign_create_docs( # [API_MAINPAGE_MD ] # [AUTOGENERATED_DOC ] # [TUTORIALS_MAINPAGE_MD ] # [ADDITIONAL_INPUT_DIRS ] # [TAGFILES ]) # # This function will configure doxygen templates and install them. # # API_MAINPAGE_MD: Optional. Specify a Markdown page to use as the main page # for API documentation. # AUTOGENERATED_DOC: Optional. Directory with the generated code. # TUTORIALS_MAINPAGE_MD: Optional. Specify a Markdown page to use as the # main page for tutorial documentation. # ADDITIONAL_INPUT_DIRS: Optional. Specify additional input directories to parse when generating documentation. # IMAGE_PATH_DIRS: Optional. Specify additional input directories where images are located # TAGFILES: Optional. Specify tagfiles for doxygen to use. It should be a list of strings like: # "${IGNITION-_DOXYGEN_TAGFILE} = ${IGNITION-_API_URL}" function(ign_create_docs) #------------------------------------ # Define the expected arguments set(options) set(oneValueArgs API_MAINPAGE_MD AUTOGENERATED_DOC TUTORIALS_MAINPAGE_MD) set(multiValueArgs "TAGFILES" "ADDITIONAL_INPUT_DIRS" "IMAGE_PATH_DIRS") option(BUILD_DOCS "Build docs" ON) if (NOT ${BUILD_DOCS}) message(STATUS "Building Documentation disabled via BUILD_DOCS=OFF") return() endif() #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_create_docs "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(required_html_files "doxygen/html/annotated.html" "doxygen/html/classes.html" "doxygen/html/files.html" "doxygen/html/functions.html" "doxygen/html/functions_func.html" "doxygen/html/functions_vars.html" "doxygen/html/functions_type.html" "doxygen/html/functions_enum.html" "doxygen/html/functions_eval.html" "doxygen/html/hierarchy.html" "doxygen/html/index.html" "doxygen/html/namespaces.html" "doxygen/html/namespacemembers.html" "doxygen/html/namespacemembers_func.html" "doxygen/html/namespacemembers_type.html" "doxygen/html/namespacemembers_vars.html" "doxygen/html/namespacemembers_enum.html" "doxygen/html/namespacemembers_eval.html" ) # Add an html file for each required_html_files, which guarantees that # all the links in header.html are valid. This is needed because # doxygen does not generate an html file if the necessary content is not # present in a project. For example, the "hierarchy.html" may not be # generated in a project that has no class hierarchy. file(READ "${IGNITION_CMAKE_DOXYGEN_DIR}/header.html" doxygen_header) file(READ "${IGNITION_CMAKE_DOXYGEN_DIR}/footer.html" doxygen_footer) string(REGEX REPLACE "\\$projectname" "Ignition ${IGN_DESIGNATION_CAP}" doxygen_header ${doxygen_header}) string(REGEX REPLACE "\\$projectnumber" "${PROJECT_VERSION_FULL}" doxygen_header ${doxygen_header}) string(REGEX REPLACE "\\$title" "404" doxygen_header ${doxygen_header}) foreach(required_file ${required_html_files}) file(WRITE ${CMAKE_BINARY_DIR}/${required_file} ${doxygen_header}) file(APPEND ${CMAKE_BINARY_DIR}/${required_file} "
No Documentation

This library does not contain the selected type of documentation.

Back

") file(APPEND ${CMAKE_BINARY_DIR}/${required_file} ${doxygen_footer}) endforeach() #-------------------------------------- # Configure documentation uploader configure_file("${IGNITION_CMAKE_DIR}/upload_doc.sh.in" ${CMAKE_BINARY_DIR}/upload_doc.sh @ONLY) #-------------------------------------- # Create man pages include(IgnRonn2Man) ign_add_manpage_target() set(IGNITION_DOXYGEN_API_MAINPAGE_MD ${ign_create_docs_API_MAINPAGE_MD}) set(IGNITION_DOXYGEN_AUTOGENERATED_DOC ${ign_create_docs_AUTOGENERATED_DOC}) set(IGNITION_DOXYGEN_TUTORIALS_MAINPAGE_MD ${ign_create_docs_TUTORIALS_MAINPAGE_MD}) set(IGNITION_DOXYGEN_TAGFILES " ") foreach(tagfile ${ign_create_docs_TAGFILES}) ign_string_append(IGNITION_DOXYGEN_TAGFILES "\"${tagfile}\"" DELIM " \\\\\\\\\n ") endforeach() set(IGNITION_DOXYGEN_ADDITIONAL_INPUT_DIRS " ") foreach(dir ${ign_create_docs_ADDITIONAL_INPUT_DIRS}) ign_string_append(IGNITION_DOXYGEN_ADDITIONAL_INPUT_DIRS "${dir}") endforeach() set(IGNITION_DOXYGEN_IMAGE_PATH " ") foreach(dir ${ign_create_docs_IMAGE_PATH_DIRS}) ign_string_append(IGNITION_DOXYGEN_IMAGE_PATH "${dir}") endforeach() find_package(Doxygen) if (DOXYGEN_FOUND AND EXISTS ${IGNITION_CMAKE_DOXYGEN_DIR}/api.in) if(EXISTS ${CMAKE_SOURCE_DIR}/tutorials) set(IGNITION_DOXYGEN_TUTORIALS_DIR ${CMAKE_SOURCE_DIR}/tutorials) else() set(IGNITION_DOXYGEN_TUTORIALS_DIR "") endif() # Configure the main API+Tutorials doxygen configuration file. This # configuration file is not used to generate the doxygen tag file, # see below. set(IGNITION_DOXYGEN_GENHTML "YES") # Be careful when manipulating IGNITION_DOXYGEN_INPUT. Doxygen is finicky # about the spaces between input files/directories. If you put each cmake # variable on a separate line to make this `set` command more readable, # then doxygen will not generate the correct/complete output. set(IGNITION_DOXYGEN_INPUT "${IGNITION_DOXYGEN_API_MAINPAGE_MD} ${IGNITION_DOXYGEN_AUTOGENERATED_DOC} ${IGNITION_DOXYGEN_TUTORIALS_DIR} ${IGNITION_DOXYGEN_TUTORIALS_MAINPAGE_MD} ${ign_doxygen_component_input_dirs} ${IGNITION_DOXYGEN_ADDITIONAL_INPUT_DIRS}") configure_file(${IGNITION_CMAKE_DOXYGEN_DIR}/api.in ${CMAKE_BINARY_DIR}/api.dox @ONLY) # The doxygen tagfile should not contain tutorial information. If tutorial # information is included in the tagfile and a downstream package also has # a page called "tutorials", then doxygen will silently fail to generate # tutorial content for the downstream package. In order to # satisfy this constraint we generate another doxygen configuration file # whose sole purpose is the generation of a project's doxygen tagfile that # contains only API information. set(IGNITION_DOXYGEN_GENHTML "NO") set(IGNITION_DOXYGEN_GENTAGFILE "${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}.tag.xml") set(IGNITION_DOXYGEN_INPUT "${ign_doxygen_component_input_dirs} ${IGNITION_DOXYGEN_AUTOGENERATED_DOC}") configure_file(${IGNITION_CMAKE_DOXYGEN_DIR}/api.in ${CMAKE_BINARY_DIR}/api_tagfile.dox @ONLY) add_custom_target(doc ALL # Generate the API tagfile ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/api_tagfile.dox # Generate the API documentation COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/api.dox WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM) install(FILES ${CMAKE_BINARY_DIR}/${PROJECT_NAME_LOWER}.tag.xml DESTINATION ${IGN_DATA_INSTALL_DIR}) endif() #-------------------------------------- # If we're configuring only to build docs, stop here if (DOC_ONLY) message(WARNING "Configuration was done in DOC_ONLY mode." " You can build documentation (make doc), but nothing else.") return() endif() endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnSetCompilerFlags.cmake0000664000175000017500000003445214160533245024347 0ustar jriverojrivero#.rst # IgnSetCompilerFlags # ------------------- # # ign_set_compiler_flags() # # Sets up compiler flags for an ignition library project # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ################################################# # Set up compiler flags macro(ign_set_compiler_flags) option(USE_IGN_RECOMMENDED_FLAGS "Build project using the compiler flags recommended by the ignition developers" ON) if(MSVC) ign_setup_msvc() elseif(UNIX) ign_setup_unix() endif() if(APPLE) ign_setup_apple() endif() # Check if we are compiling with Clang and cache it if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set(CLANG true) endif() # Check if we are compiling with GCC and cache it if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(GCC true) endif() # GCC and Clang use many of the same compilation flags, so it might be useful # to have a variable that indicates if one of them is being used. if(GCC OR CLANG) set(GCC_OR_CLANG true) endif() if(GCC_OR_CLANG) if(USE_IGN_RECOMMENDED_FLAGS) ign_setup_gcc_or_clang() endif() option(USE_HOST_SSE_FLAGS "Explicitly use compiler flags to indicate the SSE version of the host machine" TRUE) if(USE_HOST_SSE_FLAGS) ign_set_sse_flags() endif() endif() endmacro() ################################################# # Configure settings for Unix macro(ign_setup_unix) find_program(CMAKE_UNAME uname /bin /usr/bin /usr/local/bin ) if(CMAKE_UNAME) exec_program(${CMAKE_UNAME} ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_PROCESSOR) set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR} CACHE INTERNAL "processor type (i386 and x86_64)") if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") set(IGN_ADD_fPIC_TO_LIBRARIES true) endif(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64") endif(CMAKE_UNAME) endmacro() ################################################# macro(ign_setup_apple) # NOTE MacOSX provides different system versions than CMake is parsing. # The following table lists the most recent OSX versions # 9.x.x = Mac OSX Leopard (10.5) # 10.x.x = Mac OSX Snow Leopard (10.6) # 11.x.x = Mac OSX Lion (10.7) # 12.x.x = Mac OSX Mountain Lion (10.8) if(${CMAKE_SYSTEM_VERSION} LESS 10) add_definitions(-DMAC_OS_X_VERSION=1050) elseif(${CMAKE_SYSTEM_VERSION} GREATER 10 AND ${CMAKE_SYSTEM_VERSION} LESS 11) add_definitions(-DMAC_OS_X_VERSION=1060) elseif(${CMAKE_SYSTEM_VERSION} GREATER 11 AND ${CMAKE_SYSTEM_VERSION} LESS 12) add_definitions(-DMAC_OS_X_VERSION=1070) elseif(${CMAKE_SYSTEM_VERSION} GREATER 12 OR ${CMAKE_SYSTEM_VERSION} EQUAL 12) add_definitions(-DMAC_OS_X_VERSION=1080) # Use libc++ on Mountain Lion (10.8) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") else() add_definitions(-DMAC_OS_X_VERSION=0) endif() set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-undefined -Wl,dynamic_lookup") endmacro() ################################################# # Set up compilation flags for GCC or Clang macro(ign_setup_gcc_or_clang) if(ign_configure_build_HIDE_SYMBOLS_BY_DEFAULT) set(CMAKE_C_VISIBILITY_PRESET "hidden") set(CMAKE_CXX_VISIBILITY_PRESET "hidden") else() set(CMAKE_C_VISIBILITY_PRESET "default") set(CMAKE_CXX_VISIBILITY_PRESET "default") endif() ign_filter_valid_compiler_options( CUSTOM_ALL_FLAGS -Wall -Wextra -Wno-long-long -Wno-unused-value -Wfloat-equal -Wshadow -Winit-self -Wswitch-default -Wmissing-include-dirs -pedantic ) # -ggdb3: Produce comprehensive debug information that can be utilized by gdb set(CUSTOM_DEBUG_FLAGS "-ggdb3") # We use the default flags for Release set(CUSTOM_RELEASE_FLAGS "") # -UNDEBUG: Undefine the NDEBUG symbol so that assertions get triggered in # RelWithDebInfo mode # NOTE: Always make -UNDEBUG the first flag in this list so that it appears # immiediately after cmake's automatically provided -DNDEBUG flag. # Keeping them next to each other should make it more clear that the # -DNDEBUG flag is being canceled out. set(CUSTOM_RELWITHDEBINFO_FLAGS "-UNDEBUG") # We use the default flags for MinSizeRel set(CUSTOM_MINSIZEREL_FLAGS "") # -fno-omit-frame-pointer: TODO Why do we use this? # -g: Produce debug information # -pg: Produce information that is helpful for the gprof profiling tool set(CUSTOM_PROFILE_FLAGS "-fno-omit-frame-pointer -g -pg") # -g: Produce debug information. # -O0: Do absolutely no performance optimizations and reduce compilation time. # -Wformat=2: Print extra warnings for string formatting functions. # --coverage: Tell the compiler that we want our build to be instrumented for # coverage analysis. # -fno-inline: Prevent the compiler from inlining functions. Inlined functions # may confuse the coverage analysis. set(CUSTOM_C_COVERAGE_FLAGS "-g -O0 -Wformat=2 --coverage -fno-inline") set(CUSTOM_CXX_COVERAGE_FLAGS "${CUSTOM_C_COVERAGE_FLAGS}") # We add these flags depending on whether the compiler can support them, # because they cause errors when compiling with Clang. # -fno-elide-constructors: Prevent the compiler from eliding constructors. # Elision may confuse the coverage analysis. # -fno-default-inline: Prevent class members that are defined inside of their # class definition from automatically being marked as # inline functions. # ...TODO: Is this redundant with -fno-inline? # -fno-implicit-inline-templates: TODO: Why do we use this? ign_filter_valid_compiler_options( CUSTOM_CXX_COVERAGE_FLAGS -fno-elide-constructors -fno-default-inline -fno-implicit-inline-templates) # NOTE We do not use the CACHE argument when appending flags to these # variables, because appending to the CACHE will make these variables grow # with redundant flags each time cmake is run. By not using CACHE, we create # "local" copies of each of these variables, so they will not be preserved # between runs of cmake. However, since these "local" variables are created in # the top-level scope, they will be visible to all subdirectories in our # filesystem, making them effectively global. # NOTE These flags are being specified in a very particular order. First, we # specify the original set of flags, then we specify the set of flags which # are being passed to all build types, then we specify the set of flags which # are specific to each build type. When contradictory flags are given to a # compiler, whichever flag was specified last gets precedence. Therefore, we # want the flags that we're passing in now to have precedence over the # original flags for each build type, and we want the flags that are specific # to each build type to have precedence over the flags that are passed to all # build types, to make sure that each build type can customize its flags # without any conflicts. # cmake automatically provides -g for *_FLAGS_DEBUG set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${CUSTOM_ALL_FLAGS} ${CUSTOM_DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${CUSTOM_ALL_FLAGS} ${CUSTOM_DEBUG_FLAGS}") # cmake automatically provides -O3 and -DNDEBUG for *_FLAGS_RELEASE set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${CUSTOM_RELEASE_FLAGS} ${CUSTOM_ALL_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELEASE_FLAGS}") # cmake automatically provides -g, -O2, and -DNDEBUG for *_FLAGS_RELWITHDEBINFO set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELWITHDEBINFO_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${CUSTOM_ALL_FLAGS} ${CUSTOM_RELWITHDEBINFO_FLAGS}") # cmake automatically provides -Os and -DNDEBUG for *_FLAGS_MINSIZEREL set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${CUSTOM_ALL_FLAGS} ${CUSTOM_MINSIZEREL_FLAGS}") set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${CUSTOM_ALL_FLAGS} ${CUSTOM_MINSIZEREL_FLAGS}") # NONE is a custom type used in Debian, not automatically provided by cmake set(CMAKE_C_FLAGS_NONE "${CMAKE_C_FLAGS_NONE} ${CUSTOM_ALL_FLAGS} ${MSVC_MINIMAL_FLAGS}") set(CMAKE_CXX_FLAGS_NONE "${CMAKE_CXX_FLAGS_NONE} ${CUSTOM_ALL_FLAGS} ${MSVC_MINIMAL_FLAGS}") # PROFILE is a custom build type, not automatically provided by cmake set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_PROFILE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_PROFILE_FLAGS}") set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_PROFILE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_PROFILE_FLAGS}") # COVERAGE is a custom build type, not automatically provided by cmake set(CMAKE_C_FLAGS_COVERAGE "${CMAKE_C_FLAGS_COVERAGE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_C_COVERAGE_FLAGS}") set(CMAKE_CXX_FLAGS_COVERAGE "${CMAKE_CXX_FLAGS_COVERAGE} ${CUSTOM_ALL_FLAGS} ${CUSTOM_CXX_COVERAGE_FLAGS}") # NOTE: Leave CMAKE_C_FLAGS and CMAKE_CXX_FLAGS blank, because those will # be appended to all build configurations. endmacro() ################################################# # Identify what type of Streaming SIMD Extension is being used by the system and # then set the compiler's SSE flags appropriately. macro(ign_set_sse_flags) message(STATUS "\n-- Searching for host SSE information") include(IgnCheckSSE) if(SSE2_FOUND) add_compile_options(-msse -msse2) if (NOT APPLE) add_compile_options(-mfpmath=sse) message(STATUS "SSE2 found") endif() endif() if(SSE3_FOUND) add_compile_options(-msse3) message(STATUS "SSE3 found") endif() if (SSSE3_FOUND) add_compile_options(-mssse3) endif() if (SSE4_1_FOUND OR SSE4_2_FOUND) if (SSE4_1_FOUND) add_compile_options(-msse4.1) message(STATUS "SSE4.1 found") endif() if (SSE4_2_FOUND) add_compile_options(-msse4.2) message(STATUS "SSE4.2 found") endif() else() message(STATUS "SSE4 disabled.\n--") endif() endmacro() ################################################# # Set up compilation flags for Microsoft Visual Studio/C++ macro(ign_setup_msvc) # Reduce overhead by ignoring unnecessary Windows headers add_definitions(-DWIN32_LEAN_AND_MEAN) # Don't pull in the Windows min/max macros add_definitions(-DNOMINMAX) if(USE_IGN_RECOMMENDED_FLAGS) # Gy: Prevent errors caused by multiply-defined symbols # W2: Warning level 2: significant warnings. # TODO: Recommend Wall in the future. # Note: MSVC /Wall generates tons of warnings on gtest code. set(MSVC_MINIMAL_FLAGS "/Gy /W2") # Zi: Produce complete debug information # Note: We provide Zi to ordinary release mode because it does not impact # performance and can be helpful for debugging. set(MSVC_DEBUG_FLAGS "${MSVC_MINIMAL_FLAGS} /Zi") # GL: Enable Whole Program Optimization set(MSVC_RELEASE_FLAGS "${MSVC_DEBUG_FLAGS} /GL") # UNDEBUG: Undefine NDEBUG so that assertions can be triggered set(MSVC_RELWITHDEBINFO_FLAGS "${MSVC_RELEASE_FLAGS} /UNDEBUG") # INCREMENTAL:NO fix LNK4075 warning set(MSVC_RELWITHDEBINFO_LINKER_FLAGS "/INCREMENTAL:NO") # cmake automatically provides /Zi /Ob0 /Od /RTC1 set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MSVC_DEBUG_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MSVC_DEBUG_FLAGS}") # cmake automatically provides /O2 /Ob2 /DNDEBUG set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MSVC_RELEASE_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MSVC_RELEASE_FLAGS}") # cmake automatically provides /Zi /O2 /Ob1 /DNDEBUG set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${MSVC_RELWITHDEBINFO_FLAGS}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${MSVC_RELWITHDEBINFO_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} ${MSVC_RELWITHDEBINFO_LINKER_FLAGS}") # cmake automatically provides /O1 /Ob1 /DNDEBUG set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${MSVC_MINIMAL_FLAGS}") set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${MSVC_MINIMAL_FLAGS}") # NOTE: Leave CMAKE_C_FLAGS and CMAKE_CXX_FLAGS blank, because # those will be appended to all build configurations. # TODO: What flags should be set for PROFILE and COVERAGE build types? # Is it even possible to generate those build types on Windows? endif() # Use the dynamically loaded run-time library in Windows by default. The # dynamically loaded run-time allows dynamically allocated objects to be # passed between different DLLs, which is important for our plugin-based # framework. # # In some cases, a user might want to compile with the static runtime. This # should ONLY be done if they do not intend to use the ignition library as # part of a plugin-based framework. option(IGN_USE_STATIC_RUNTIME "Use the static runtime (strongly discouraged)" OFF) if(BUILD_SHARED_LIBS) # Users should not choose the static runtime unless they are compiling a # static library, so we completely disable this option if BUILD_SHARED_LIBS # is turned on. set(IGN_USE_STATIC_RUNTIME OFF CACHE BOOL "Use the static runtime (strongly discouraged)" FORCE) endif() if(IGN_USE_STATIC_RUNTIME) foreach(build_type DEBUG RELEASE RELWITHDEBINFO MINSIZEREL NONE) foreach(lang C CXX) set(flags_var CMAKE_${lang}_FLAGS_${build_type}) string(REGEX REPLACE "/MD" "/MT" ${flags_var} "${${flags_var}}") endforeach() endforeach() endif() # We always want this flag to be specified so we get standard-compliant # exception handling. # EHsc: Use standard-compliant exception handling add_compile_options("/EHsc") endmacro() ign-cmake-ignition-cmake2_2.10.0/cmake/FindAVDEVICE.cmake0000664000175000017500000000364614160533245022476 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find AV device. set(av_major ${AVDEVICE_FIND_VERSION_MAJOR}) set(av_minor ${AVDEVICE_FIND_VERSION_MINOR}) set(av_patch ${AVDEVICE_FIND_VERSION_PATCH}) include(IgnPkgConfig) ign_pkg_check_modules_quiet(AVDEVICE "libavdevice >= ${av_major}.${av_minor}.${av_patch}") if(NOT AVDEVICE_FOUND) include(IgnManualSearch) ign_manual_search(AVDEVICE HEADER_NAMES "libavdevice/avdevice.h" LIBRARY_NAMES "avdevice") # Version check if(AVDEVICE_FOUND) file(READ "${AVDEVICE_INCLUDE_DIRS}/libavdevice/version.h" ver_file) string(REGEX MATCH "LIBAVDEVICE_VERSION_MAJOR[ \t\r\n]+([0-9]*)" _ ${ver_file}) set(ver_major ${CMAKE_MATCH_1}) string(REGEX MATCH "LIBAVDEVICE_VERSION_MINOR[ \t\r\n]+([0-9]*)" _ ${ver_file}) set(ver_minor ${CMAKE_MATCH_1}) string(REGEX MATCH "LIBAVDEVICE_VERSION_MICRO[ \t\r\n]+([0-9]*)" _ ${ver_file}) set(ver_patch ${CMAKE_MATCH_1}) set(AVDEVICE_VERSION "${ver_major}.${ver_minor}.${ver_patch}") if(AVDEVICE_VERSION VERSION_LESS AVDEVICE_FIND_VERSION) set(AVDEVICE_FOUND FALSE) endif() endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( AVDEVICE REQUIRED_VARS AVDEVICE_FOUND)ign-cmake-ignition-cmake2_2.10.0/cmake/ignition-component-config.cmake.in0000664000175000017500000001035314160533245026170 0ustar jriverojrivero# - Config file for the @component_pkg_name@ component # # This should only be invoked by @PKG_NAME@-config.cmake. # # To load this component into your project, use: # find_package(@PKG_NAME@ COMPONENTS @component_name@) # # This creates the following targets: # # Component library target - @import_target_name@ # Alternative target name - @simple_import_name@ # Core library + all requested components - @ign_namespace@requested # # Use target_link_libraries() to link your library or executable to one of the # above targets. # # We also provide the following variable for backwards compatibility, but use of # this is discouraged: # # @component_pkg_name@_LIBRARY - Component library (actually contains @simple_import_name@) # # We will also set @component_pkg_name@_FOUND to indicate that the component was found. # ################################################################################ # We explicitly set the desired cmake version to ensure that the policy settings # of users or of toolchains do not result in the wrong behavior for our modules. # Note that the call to find_package(~) will PUSH a new policy stack before # taking on these version settings, and then that stack will POP after the # find_package(~) has exited, so this will not affect the cmake policy settings # of a caller. cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) if(@component_pkg_name@_CONFIG_INCLUDED) return() endif() set(@component_pkg_name@_CONFIG_INCLUDED TRUE) if(NOT @component_pkg_name@_FIND_QUIETLY) message(STATUS "Looking for @component_pkg_name@ -- found version @PROJECT_VERSION_FULL@") endif() @PACKAGE_INIT@ # Get access to the find_dependency utility include(CMakeFindDependencyMacro) # Find ignition-cmake, because we need its modules in order to find the rest of # our dependencies. find_dependency(ignition-cmake@IGNITION_CMAKE_VERSION_MAJOR@) # Set the REQUIRED flag for the find_package(~) calls on this component's # dependencies. if(@component_pkg_name@_FIND_REQUIRED) set(ign_package_required REQUIRED) else() set(ign_package_required "") endif() # Set the QUIET flag for the find_package(~) calls on this component's # dependencies. if(@component_pkg_name@_FIND_QUIETLY) set(ign_package_quiet QUIET) else() set(ign_package_quiet "") endif() # -------------------------------- # Find the dependencies that are specific to this component (if nothing is # below, then the component has no additional dependencies). We use # find_package(~) instead of find_dependency(~) here so that we can support # COMPONENT arguments. # # TODO: When we migrate to cmake-3.9+, change these to find_dependency(~), # because at that point the find_dependency(~) function will support # the COMPONENT argument. if(NOT @component_pkg_name@_FIND_QUIETLY) message(STATUS "Searching for dependencies of @component_pkg_name@") endif() @component_cmake_dependencies@ # -------------------------------- if(NOT TARGET @import_target_name@) include("${CMAKE_CURRENT_LIST_DIR}/@target_output_filename@") # Create a simplified imported target name for the @component@ library. # You can link to this target instead of the @component@ library. add_library(@simple_import_name@ INTERFACE IMPORTED) set_target_properties(@simple_import_name@ PROPERTIES INTERFACE_LINK_LIBRARIES "@import_target_name@") # Note: In a future version of cmake, we can replace this with an ALIAS target endif() # Create the "requested" target if it does not already exist if(NOT TARGET @ign_namespace@requested) add_library(@ign_namespace@requested INTERFACE IMPORTED) endif() # Link the @component@ library to the "requested" target get_target_property(ign_requested_components @ign_namespace@requested INTERFACE_LINK_LIBRARIES) if(NOT ign_requested_components) set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "@import_target_name@") else() set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "${ign_requested_components};@import_target_name@") endif() set(@component_pkg_name@_LIBRARY @import_target_name@) # This macro is used by ignition-cmake to automatically configure the pkgconfig # files for ignition projects. ign_pkg_config_entry(@component_pkg_name@ "@component_pkg_name@") ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnBullet.cmake0000664000175000017500000000311514160533245023164 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2019 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Copyright (c) 2011-2019, The DART development contributors # All rights reserved. # # The list of contributors can be found at: # https://github.com/dartsim/dart/blob/master/LICENSE # # This file is provided under the "BSD-style" License ######################################## set(ign_quiet_arg) if(IgnBullet_FIND_QUIETLY) set(ign_quiet_arg QUIET) endif() # Bullet. Force MODULE mode to use the FindBullet.cmake file distributed with # CMake. Otherwise, we may end up using the BulletConfig.cmake file distributed # with Bullet, which uses relative paths and may break transitive dependencies. find_package(Bullet MODULE ${ign_quiet_arg}) set(IgnBullet_FOUND false) # create Bullet target if(BULLET_FOUND) set(IgnBullet_FOUND true) ign_import_target(IgnBullet TARGET_NAME IgnBullet::IgnBullet LIB_VAR BULLET_LIBRARIES INCLUDE_VAR BULLET_INCLUDE_DIRS ) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnCheckSSE.cmake0000664000175000017500000002745614160533245022542 0ustar jriverojrivero# Copyright (c) 2012 Petroules Corporation. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. Redistributions in binary # form must reproduce the above copyright notice, this list of conditions and # the following disclaimer in the documentation and/or other materials # provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Modified for ignition libraries - 2017 # Based on the Qt 5 processor detection code, so should be very accurate # https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h # Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64) # Regarding POWER/PowerPC, just as is noted in the Qt source, # "There are many more known variants/revisions that we do not handle/detect." set(archdetect_c_code " #if defined(__arm__) || defined(__TARGET_ARCH_ARM) #if defined(__ARM_ARCH_7__) \\ || defined(__ARM_ARCH_7A__) \\ || defined(__ARM_ARCH_7R__) \\ || defined(__ARM_ARCH_7M__) \\ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7) #error cmake_ARCH armv7 #elif defined(__ARM_ARCH_6__) \\ || defined(__ARM_ARCH_6J__) \\ || defined(__ARM_ARCH_6T2__) \\ || defined(__ARM_ARCH_6Z__) \\ || defined(__ARM_ARCH_6K__) \\ || defined(__ARM_ARCH_6ZK__) \\ || defined(__ARM_ARCH_6M__) \\ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6) #error cmake_ARCH armv6 #elif defined(__ARM_ARCH_5TEJ__) \\ || (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5) #error cmake_ARCH armv5 #else #error cmake_ARCH arm #endif #elif defined(__i386) || defined(__i386__) || defined(_M_IX86) #error cmake_ARCH i386 #elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64) #error cmake_ARCH x86_64 #elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64) #error cmake_ARCH ia64 #elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\ || defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\ || defined(_M_MPPC) || defined(_M_PPC) #if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__) #error cmake_ARCH ppc64 #else #error cmake_ARCH ppc #endif #endif #error cmake_ARCH unknown ") # Set ppc_support to TRUE before including this file or ppc and ppc64 # will be treated as invalid architectures since they are no longer supported by Apple if(APPLE AND CMAKE_OSX_ARCHITECTURES) # On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set # First let's normalize the order of the values # Note that it's not possible to compile PowerPC applications if you are using # the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we # disable it by default # See this page for more information: # http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4 # Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime. # On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise. foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES}) if("${osx_arch}" STREQUAL "ppc" AND ppc_support) set(osx_arch_ppc TRUE) elseif("${osx_arch}" STREQUAL "i386") set(osx_arch_i386 TRUE) elseif("${osx_arch}" STREQUAL "x86_64") set(osx_arch_x86_64 TRUE) elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support) set(osx_arch_ppc64 TRUE) else() message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}") endif() endforeach() # Now add all the architectures in our normalized order if(osx_arch_ppc) list(APPEND ARCH ppc) endif() if(osx_arch_i386) list(APPEND ARCH i386) endif() if(osx_arch_x86_64) list(APPEND ARCH x86_64) endif() if(osx_arch_ppc64) list(APPEND ARCH ppc64) endif() else() file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}") enable_language(C) # Detect the architecture in a rather creative way... # This compiles a small C program which is a series of ifdefs that selects a # particular #error preprocessor directive whose message string contains the # target architecture. The program will always fail to compile (both because # file is not a valid C program, and obviously because of the presence of the # #error preprocessor directives... but by exploiting the preprocessor in this # way, we can detect the correct target architecture even when cross-compiling, # since the program itself never needs to be run (only the compiler/preprocessor) try_run( run_result_unused compile_result_unused "${CMAKE_BINARY_DIR}" "${CMAKE_BINARY_DIR}/arch.c" COMPILE_OUTPUT_VARIABLE ARCH CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES} ) # Parse the architecture name from the compiler output string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}") # Get rid of the value marker leaving just the architecture name string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}") # If we are compiling with an unknown architecture this variable should # already be set to "unknown" but in the case that it's empty (i.e. due # to a typo in the code), then set it to unknown if (NOT ARCH) set(ARCH unknown) endif() endif() # Check if SSE instructions are available on the machine where # the project is compiled. IF (ARCH MATCHES "i386" OR ARCH MATCHES "x86_64") IF(CMAKE_SYSTEM_NAME MATCHES "Linux") EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO) STRING(REGEX REPLACE "^.*(sse2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "sse2" "${SSE_THERE}" SSE2_TRUE) IF (SSE2_TRUE) set(SSE2_FOUND true CACHE BOOL "SSE2 available on host") ELSE (SSE2_TRUE) set(SSE2_FOUND false CACHE BOOL "SSE2 available on host") ENDIF (SSE2_TRUE) # /proc/cpuinfo apparently omits sse3 :( STRING(REGEX REPLACE "^.*[^s](sse3).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "sse3" "${SSE_THERE}" SSE3_TRUE) IF (NOT SSE3_TRUE) STRING(REGEX REPLACE "^.*(T2300).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "T2300" "${SSE_THERE}" SSE3_TRUE) ENDIF (NOT SSE3_TRUE) STRING(REGEX REPLACE "^.*(ssse3).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "ssse3" "${SSE_THERE}" SSSE3_TRUE) IF (SSE3_TRUE OR SSSE3_TRUE) set(SSE3_FOUND true CACHE BOOL "SSE3 available on host") ELSE (SSE3_TRUE OR SSSE3_TRUE) set(SSE3_FOUND false CACHE BOOL "SSE3 available on host") ENDIF (SSE3_TRUE OR SSSE3_TRUE) IF (SSSE3_TRUE) set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host") ELSE (SSSE3_TRUE) set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host") ENDIF (SSSE3_TRUE) STRING(REGEX REPLACE "^.*(sse4_1).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "sse4_1" "${SSE_THERE}" SSE41_TRUE) IF (SSE41_TRUE) set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host") ELSE (SSE41_TRUE) set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host") ENDIF (SSE41_TRUE) STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE) IF (SSE42_TRUE) set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host") ELSE (SSE42_TRUE) set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host") ENDIF (SSE42_TRUE) ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Darwin") EXEC_PROGRAM("/usr/sbin/sysctl -n machdep.cpu.features" OUTPUT_VARIABLE CPUINFO) STRING(REGEX REPLACE "^.*[^S](SSE2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "SSE2" "${SSE_THERE}" SSE2_TRUE) IF (SSE2_TRUE) set(SSE2_FOUND true CACHE BOOL "SSE2 available on host") ELSE (SSE2_TRUE) set(SSE2_FOUND false CACHE BOOL "SSE2 available on host") ENDIF (SSE2_TRUE) STRING(REGEX REPLACE "^.*[^S](SSE3).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "SSE3" "${SSE_THERE}" SSE3_TRUE) IF (SSE3_TRUE) set(SSE3_FOUND true CACHE BOOL "SSE3 available on host") ELSE (SSE3_TRUE) set(SSE3_FOUND false CACHE BOOL "SSE3 available on host") ENDIF (SSE3_TRUE) STRING(REGEX REPLACE "^.*(SSSE3).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "SSSE3" "${SSE_THERE}" SSSE3_TRUE) IF (SSSE3_TRUE) set(SSSE3_FOUND true CACHE BOOL "SSSE3 available on host") ELSE (SSSE3_TRUE) set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host") ENDIF (SSSE3_TRUE) STRING(REGEX REPLACE "^.*(SSE4.1).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "SSE4.1" "${SSE_THERE}" SSE41_TRUE) IF (SSE41_TRUE) set(SSE4_1_FOUND true CACHE BOOL "SSE4.1 available on host") ELSE (SSE41_TRUE) set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host") ENDIF (SSE41_TRUE) STRING(REGEX REPLACE "^.*(SSE4.2).*$" "\\1" SSE_THERE ${CPUINFO}) STRING(COMPARE EQUAL "SSE4.2" "${SSE_THERE}" SSE42_TRUE) IF (SSE42_TRUE) set(SSE4_2_FOUND true CACHE BOOL "SSE4.2 available on host") ELSE (SSE42_TRUE) set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host") ENDIF (SSE42_TRUE) ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Windows") # TODO set(SSE2_FOUND true CACHE BOOL "SSE2 available on host") set(SSE3_FOUND false CACHE BOOL "SSE3 available on host") set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host") set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host") set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host") ELSE(CMAKE_SYSTEM_NAME MATCHES "Linux") set(SSE2_FOUND true CACHE BOOL "SSE2 available on host") set(SSE3_FOUND false CACHE BOOL "SSE3 available on host") set(SSSE3_FOUND false CACHE BOOL "SSSE3 available on host") set(SSE4_1_FOUND false CACHE BOOL "SSE4.1 available on host") set(SSE4_2_FOUND false CACHE BOOL "SSE4.2 available on host") ENDIF(CMAKE_SYSTEM_NAME MATCHES "Linux") ENDIF(ARCH MATCHES "i386" OR ARCH MATCHES "x86_64") if(NOT SSE2_FOUND) MESSAGE(STATUS "Could not find hardware support for SSE2 on this machine.") endif(NOT SSE2_FOUND) if(NOT SSE3_FOUND) MESSAGE(STATUS "Could not find hardware support for SSE3 on this machine.") endif(NOT SSE3_FOUND) if(NOT SSSE3_FOUND) MESSAGE(STATUS "Could not find hardware support for SSSE3 on this machine.") endif(NOT SSSE3_FOUND) if(NOT SSE4_1_FOUND) MESSAGE(STATUS "Could not find hardware support for SSE4.1 on this machine.") endif(NOT SSE4_1_FOUND) if(NOT SSE4_2_FOUND) MESSAGE(STATUS "Could not find hardware support for SSE4.2 on this machine.") endif(NOT SSE4_2_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/FindSWSCALE.cmake0000664000175000017500000000214114160533245022376 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find libswscale format include(IgnPkgConfig) ign_pkg_check_modules_quiet(SWSCALE libswscale) if(NOT SWSCALE_FOUND) include(IgnManualSearch) ign_manual_search(SWSCALE HEADER_NAMES "libswscale/swscale.h" LIBRARY_NAMES "swscale") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( SWSCALE REQUIRED_VARS SWSCALE_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/IgnConfigureProject.cmake0000664000175000017500000002136114160533245024407 0ustar jriverojrivero#.rst # IgnConfigureProject # ------------------- # # ign_configure_project([VERSION_SUFFIX ]) # # Sets up an ignition library project. # # NO_IGNITION_PREFIX: Optional. Don't use ignition as prefix in # cmake project name. # REPLACE_IGNITION_INCLUDE_PATH: Optional. Specify include folder # names to replace the default value of # ignition/${IGN_DESIGNATION} # VERSION_SUFFIX: Optional. Specify a prerelease version suffix. # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################# # Initialize the ignition project macro(ign_configure_project) #------------------------------------ # Define the expected arguments set(options NO_IGNITION_PREFIX) set(oneValueArgs REPLACE_IGNITION_INCLUDE_PATH VERSION_SUFFIX) set(multiValueArgs) # We are not using multiValueArgs yet #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_configure_project "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # Note: The following are automatically defined by project(~) in cmake v3: # PROJECT_NAME # PROJECT_VERSION_MAJOR # PROJECT_VERSION_MINOR # PROJECT_VERSION_PATCH if(ign_configure_project_VERSION_SUFFIX) set(PROJECT_VERSION_SUFFIX ${ign_configure_project_VERSION_SUFFIX}) endif() #============================================================================ # Extract the designation #============================================================================ set(IGN_DESIGNATION ${PROJECT_NAME}) # Remove the leading "ignition-" string(REGEX REPLACE "ignition-" "" IGN_DESIGNATION ${IGN_DESIGNATION}) # Remove the trailing version number string(REGEX REPLACE "[0-9]+" "" IGN_DESIGNATION ${IGN_DESIGNATION}) #============================================================================ # Set project variables #============================================================================ if(ign_configure_project_NO_IGNITION_PREFIX) set(PROJECT_NAME_NO_VERSION ${IGN_DESIGNATION}) else() set(PROJECT_NAME_NO_VERSION "ignition-${IGN_DESIGNATION}") endif() string(TOLOWER ${PROJECT_NAME_NO_VERSION} PROJECT_NAME_NO_VERSION_LOWER) string(TOUPPER ${PROJECT_NAME_NO_VERSION} PROJECT_NAME_NO_VERSION_UPPER) string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) string(TOUPPER ${PROJECT_NAME} PROJECT_NAME_UPPER) string(TOLOWER ${IGN_DESIGNATION} IGN_DESIGNATION_LOWER) string(TOUPPER ${IGN_DESIGNATION} IGN_DESIGNATION_UPPER) string(SUBSTRING ${IGN_DESIGNATION} 0 1 IGN_DESIGNATION_FIRST_LETTER) string(TOUPPER ${IGN_DESIGNATION_FIRST_LETTER} IGN_DESIGNATION_FIRST_LETTER) string(REGEX REPLACE "^.(.*)" "${IGN_DESIGNATION_FIRST_LETTER}\\1" IGN_DESIGNATION_CAP "${IGN_DESIGNATION}") set(PROJECT_EXPORT_NAME ${PROJECT_NAME_LOWER}) set(PROJECT_LIBRARY_TARGET_NAME ${PROJECT_NAME_LOWER}) if(ign_configure_project_REPLACE_IGNITION_INCLUDE_PATH) set(PROJECT_INCLUDE_DIR ${ign_configure_project_REPLACE_IGNITION_INCLUDE_PATH}) else() set(PROJECT_INCLUDE_DIR ignition/${IGN_DESIGNATION}) endif() # version . set(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}) # version .. set(PROJECT_VERSION_FULL ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}) # The full version of the project, but without any prerelease suffix set(PROJECT_VERSION_FULL_NO_SUFFIX ${PROJECT_VERSION_FULL}) if(PROJECT_VERSION_SUFFIX) # Append the prerelease suffix to PROJECT_VERSION_FULL if this has a suffix # version ..~ set(PROJECT_VERSION_FULL ${PROJECT_VERSION_FULL}~${PROJECT_VERSION_SUFFIX}) endif() set(PKG_NAME ${PROJECT_NAME_LOWER}) message(STATUS "${PROJECT_NAME} version ${PROJECT_VERSION_FULL}") #============================================================================ # Identify the operating system ign_check_os() #============================================================================ # Create package information ign_setup_packages() #============================================================================ # Initialize build errors/warnings # NOTE: We no longer use CACHE for these variables because it was set to # "INTERNAL", making it unnecessary to cache them. As long as this macro is # called from the top-level scope, these variables will effectively be global, # even without putting them in the cache. If this macro is not being called # from the top-level scope, then it is being used incorrectly. set(build_errors "") set(build_warnings "") #============================================================================ # Initialize the list of -config.cmake dependencies set(PROJECT_CMAKE_DEPENDENCIES) # Initialize the list of .pc Requires set(PROJECT_PKGCONFIG_REQUIRES) # Initialize the list of .pc Requires.private set(PROJECT_PKGCONFIG_REQUIRES_PRIVATE) # Initialize the list of .pc Libs set(PROJECT_PKGCONFIG_LIBS) # Initialize the list of .pc Libs.private set(PROJECT_PKGCONFIG_LIBS_PRIVATE) #============================================================================ # We turn off extensions because (1) we do not ever want to use non-standard # compiler extensions, and (2) this variable is on by default, causing cmake # to choose the flag -std=gnu++14 instead of -std=c++14 when the C++14 # features are requested. Explicitly turning this flag off will force cmake to # choose -std=c++14. set(CMAKE_CXX_EXTENSIONS off) #============================================================================ # Put all runtime objects (executables and DLLs) into a single directory. # This helps executables (e.g. tests) to run from the build directory on # Windows. The DLLs that we build for this library needs to be available to # the executables that depend on them. set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) # Put all libraries (.so, static .lib) into a single directory. This is just # for convenience. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) # Put all archive libraries (export .lib) into the lib directory. This is # just for convenience. set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) endmacro() ################################################# # Check the OS type. macro(ign_check_os) # CMake does not distinguish Linux from other Unices. string(REGEX MATCH "Linux" PLAYER_OS_LINUX ${CMAKE_SYSTEM_NAME}) # Nor *BSD string(REGEX MATCH "BSD" PLAYER_OS_BSD ${CMAKE_SYSTEM_NAME}) # Or Solaris. I'm seeing a trend, here string(REGEX MATCH "SunOS" PLAYER_OS_SOLARIS ${CMAKE_SYSTEM_NAME}) # Windows is easy (for once) if(WIN32) set(PLAYER_OS_WIN TRUE BOOL INTERNAL) endif() # Check if it's an Apple OS if(APPLE) # Check if it's OS X or another MacOS (that's got to be pretty unlikely) string(REGEX MATCH "Darwin" PLAYER_OS_OSX ${CMAKE_SYSTEM_NAME}) if(NOT PLAYER_OS_OSX) set(PLAYER_OS_MACOS TRUE BOOL INTERNAL) endif() endif() # QNX if(QNXNTO) set(PLAYER_OS_QNX TRUE BOOL INTERNAL) endif() if(PLAYER_OS_LINUX) message(STATUS "Operating system is Linux") elseif(PLAYER_OS_BSD) message(STATUS "Operating system is BSD") elseif(PLAYER_OS_WIN) message(STATUS "Operating system is Windows") elseif(PLAYER_OS_OSX) message(STATUS "Operating system is Apple MacOS X") elseif(PLAYER_OS_MACOS) message(STATUS "Operating system is Apple MacOS (not OS X)") elseif(PLAYER_OS_QNX) message(STATUS "Operating system is QNX") elseif(PLAYER_OS_SOLARIS) message(STATUS "Operating system is Solaris") else(PLAYER_OS_LINUX) message(STATUS "Operating system is generic Unix") endif() ################################################# # Check for non-case-sensitive filesystems execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/tools/case_sensitive_filesystem RESULT_VARIABLE FILESYSTEM_CASE_SENSITIVE_RETURN) if (${FILESYSTEM_CASE_SENSITIVE_RETURN} EQUAL 0) set(FILESYSTEM_CASE_SENSITIVE TRUE) else() set(FILESYSTEM_CASE_SENSITIVE FALSE) endif() endmacro() ign-cmake-ignition-cmake2_2.10.0/cmake/cpack_options.cmake.in0000664000175000017500000000252514160533245023743 0ustar jriverojriveroset(CPACK_PACKAGE_NAME "@PROJECT_NAME_NO_VERSION@") set(CPACK_PACKAGE_VENDOR "osrfoundation.org") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "A set of @IGN_DESIGNATION@ classes for robot applications.") set(CPACK_PACKAGE_INSTALL_DIRECTORY "@PROJECT_NAME_NO_VERSION_LOWER@") set(CPACK_RESOURCE_FILE_LICENSE "@CMAKE_CURRENT_SOURCE_DIR@/LICENSE") set(CPACK_RESOURCE_FILE_README "@CMAKE_CURRENT_SOURCE_DIR@/README.md") set(CPACK_PACKAGE_DESCRIPTION_FILE "@CMAKE_CURRENT_SOURCE_DIR@/README.md") set(CPACK_PACKAGE_MAINTAINER "Nate Koenig ") set(CPACK_PACKAGE_CONTACT "Nate Koenig ") set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "@DPKG_ARCH@") set(CPACK_DEBIAN_PACKAGE_DEPENDS "@DEBIAN_PACKAGE_DEPENDS@") set(CPACK_DEBIAN_PACKAGE_SECTION "devel") set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "A set of @IGN_DESIGNATION@ classes for robot applications.") set(CPACK_RPM_PACKAGE_ARCHITECTURE "@DPKG_ARCH@") set(CPACK_RPM_PACKAGE_REQUIRES "@DEBIAN_PACKAGE_DEPENDS@") set(CPACK_RPM_PACKAGE_DESCRIPTION "A set of @IGN_DESIGNATION@ classes for robot applications.") set (CPACK_PACKAGE_FILE_NAME "@PROJECT_NAME_NO_VERSION_LOWER@-@PROJECT_VERSION_FULL@") set (CPACK_SOURCE_PACKAGE_FILE_NAME "@PROJECT_NAME_NO_VERSION_LOWER@-@PROJECT_VERSION_FULL@") ign-cmake-ignition-cmake2_2.10.0/cmake/IgnImportTarget.cmake0000664000175000017500000001634614160533245023567 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # ign_import_target( [INTERFACE] # [TARGET_NAME ] # [LIB_VAR ] # [INCLUDE_VAR ] # [CFLAGS_VAR ]) # # This macro will create an imported target based on the variables pertaining # to , such as _LIBRARIES, _INCLUDE_DIRS, and # _CFLAGS. Optionally, you can provide TARGET_NAME followed by a # string, which will then be used as the name of the imported target. If # TARGET_NAME is not provided, the name of the imported target will default to # ::. # # INTERFACE: Optional. Use INTERFACE when the target does not actually provide # a library that needs to be linked against (e.g. it is a header-only # library, or the target is just used to specify compiler flags). # # TARGET_NAME: Optional. Explicitly specify the desired imported target name. # Default is ::. # # LIB_VAR: Optional. Explicitly specify the name of the library variable for # this package. Default is _LIBRARIES. # # INCLUDE_VAR: Optional. Explicitly specify the name of the include directory # variable for this package. Default is _INCLUDE_DIRS. # # CFLAGS_VAR: Optional. Explicitly specify the name of the cflags variable for # this package. Default is _CFLAGS. # macro(ign_import_target package) #------------------------------------ # Define the expected arguments set(options "INTERFACE") set(oneValueArgs "TARGET_NAME" "LIB_VAR" "INCLUDE_VAR" "CFLAGS_VAR") set(multiValueArgs) # We are not using multiValueArgs yet #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_import_target "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #------------------------------------ # Check if a target name has been provided, otherwise use # ${package}::{$package} as the target name. if(ign_import_target_TARGET_NAME) set(target_name ${ign_import_target_TARGET_NAME}) else() set(target_name ${package}::${package}) endif() if(NOT TARGET ${target_name}) #------------------------------------ # Use default versions of these build variables if custom versions were not # provided. if(NOT ign_import_target_LIB_VAR) set(ign_import_target_LIB_VAR ${package}_LIBRARIES) endif() if(NOT ign_import_target_INCLUDE_VAR) set(ign_import_target_INCLUDE_VAR ${package}_INCLUDE_DIRS) endif() if(NOT ign_import_target_CFLAGS_VAR) set(ign_import_target_CFLAGS_VAR ${package}_CFLAGS) endif() #------------------------------------ # Link against this "imported" target by saying # target_link_libraries(mytarget package::package), instead of linking # against the variable package_LIBRARIES with the old-fashioned # target_link_libraries(mytarget ${package_LIBRARIES} if(NOT ign_import_target_INTERFACE) add_library(${target_name} UNKNOWN IMPORTED) else() add_library(${target_name} INTERFACE IMPORTED) endif() # Do not bother with the IMPORTED_LOCATION or IMPORTED_IMPLIB variables if it # is an INTERFACE target. if(NOT ign_import_target_INTERFACE) if(${ign_import_target_LIB_VAR}) _ign_sort_libraries(${target_name} ${${ign_import_target_LIB_VAR}}) endif() endif() if(${ign_import_target_LIB_VAR}) set_target_properties(${target_name} PROPERTIES INTERFACE_LINK_LIBRARIES "${${ign_import_target_LIB_VAR}}") endif() if(${ign_import_target_INCLUDE_VAR}) # TODO: In a later version of cmake, it should be possible to replace this # with # # target_include_directories(${target_name} INTERFACE ${${ign_import_target_INCLUDE_VAR}}) # # But this will not be possible until we are using whichever version of cmake # the PR https://gitlab.kitware.com/cmake/cmake/merge_requests/1264 # is available for. set_property( TARGET ${target_name} PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${${ign_import_target_INCLUDE_VAR}}) endif() if(${ign_import_target_CFLAGS_VAR}) # TODO: See note above. We should eventually be able to replace this with # target_compile_options(${target_name} INTERFACE ${${ign_import_target_CFLAGS_VAR}}) set_property( TARGET ${target_name} PROPERTY INTERFACE_COMPILE_OPTIONS ${${ign_import_target_CFLAGS_VAR}}) endif() # What about linker flags? Is there no target property for that? endif() endmacro() # This is an awkward hack to give the package both an IMPORTED_LOCATION and # a set of INTERFACE_LIBRARIES in the event that PkgConfig returns multiple # libraries for this package. It seems that IMPORTED_LOCATION cannot support # specifying multiple libraries, so if we have multiple libraries, we need to # pass them into INTERFACE_LINK_LIBRARIES. However, if IMPORTED_LOCATION is # missing from the target, the dependencies do not get configured correctly by # the generator expressions, and the build system will try to link to a nonsense # garbage file. # # TODO: Figure out if there is a better way to fill in the various library # properties of an imported target. function(_ign_sort_libraries target_name first_lib) if(MSVC) # Note: For MSVC, we only care about the "import library" which is the # library ending in *.lib. The linker only needs to be told where the # *.lib library is. The dynamic library (*.dll) only needs to be visible # to the program at run-time, not at compile or link time. Furthermore, # find_library on Windows only looks for *.lib files, so we expect that # results of the form package_LIBRARIES will contain *.lib files when # running on Windows. IMPORTED_IMPLIB is the target property that # indicates the "import library" of an "imported target", so that is # the property that will fill in first and foremost. # # TODO: How does MinGW handle libraries? set_target_properties(${target_name} PROPERTIES IMPORTED_IMPLIB "${first_lib}") endif() set_target_properties(${target_name} PROPERTIES IMPORTED_LOCATION "${first_lib}") foreach(extra_lib ${ARGN}) set_target_properties(${target_name} PROPERTIES INTERFACE_LINK_LIBRARIES "${extra_lib}") endforeach() get_target_property(ill ${target_name} INTERFACE_LINK_LIBRARIES) set_target_properties(${target_name} PROPERTIES IMPORTED_LINK_INTERFACE_LIBRARIES ${ill}) set_target_properties(${target_name} PROPERTIES IMPORTED_LINK_DEPENDENT_LIBRARIES ${ill}) endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/FindSQLite3.cmake0000664000175000017500000000324714160533245022531 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find SQLite3 # # Usage of this module is as follows: # # find_package(SQLite3 [VERSION [.[.]]]) # # Variables defined by this module: # # SQLite3::SQLite3 Imported target for sqlite3 # SQLite3_FOUND System has sqlite3 library and headers if(SQLite3_FIND_VERSION) ign_pkg_check_modules_quiet(SQLite3 "sqlite3 >= ${SQLite3_FIND_VERSION}") else() ign_pkg_check_modules_quiet(SQLite3 "sqlite") endif() if(MSVC) set(SQLite3_FOUND TRUE) find_library(SQLite3_LIBRARIES sqlite3) if(NOT SQLite3_LIBRARIES) set(SQLite3_FOUND FALSE) if(NOT SQLite3_FIND_QUIETLY) message(STATUS "Looking for sqlite3 library - not found") endif() endif() find_path(SQLite3_INCLUDE_DIRS sqlite3.h) if(NOT SQLite3_INCLUDE_DIRS) set(SQLite3_FOUND FALSE) if(NOT SQLite3_FIND_QUIETLY) message(STATUS "Looking for sqlite header (sqlite3.h) - not found") endif() endif() ign_import_target(SQLite3) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnConfigureBuild.cmake0000664000175000017500000003374514160533245024051 0ustar jriverojrivero#.rst # IgnBuildProject # ------------------- # # ign_configure_build() # # Configures the build rules of an ignition library project. # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################# # Configure the build of the ignition project # Pass the argument HIDE_SYMBOLS_BY_DEFAULT to configure symbol visibility so # that symbols are hidden unless explicitly marked as visible. # Pass the argument QUIT_IF_BUILD_ERRORS to have this macro quit cmake when the # build_errors macro(ign_configure_build) #============================================================================ # Parse the arguments that are passed in set(options HIDE_SYMBOLS_BY_DEFAULT QUIT_IF_BUILD_ERRORS) set(oneValueArgs) set(multiValueArgs COMPONENTS) cmake_parse_arguments(ign_configure_build "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #============================================================================ # Examine the build type. If we do not recognize the type, we will generate # an error, so this must come before the error handling. ign_parse_build_type() #============================================================================ # Ask whether we should make a shared or static library. option(BUILD_SHARED_LIBS "Set this to true to generate shared libraries (recommended), or false for static libraries" ON) #============================================================================ # Print warnings and errors if(build_warnings) set(all_warnings " CONFIGURATION WARNINGS:") foreach (msg ${build_warnings}) ign_string_append(all_warnings " -- ${msg}" DELIM "\n") endforeach () message(WARNING "${all_warnings}") endif (build_warnings) if(build_errors) message(SEND_ERROR "-- BUILD ERRORS: These must be resolved before compiling.") foreach(msg ${build_errors}) message(SEND_ERROR "-- ${msg}") endforeach() message(SEND_ERROR "-- END BUILD ERRORS\n") set(error_str "Errors encountered in build. Please see BUILD ERRORS above.") if(ign_configure_build_QUIT_IF_BUILD_ERRORS) message(FATAL_ERROR "${error_str}") else() message(WARNING "${error_str}") endif() endif() #============================================================================ # If there are no build errors, try building if(NOT build_errors) #-------------------------------------- # Turn on testing include(CTest) enable_testing() #-------------------------------------- # Set up the compiler flags ign_set_compiler_flags() #-------------------------------------- # Set up the compiler feature flags to help us choose our standard ign_set_cxx_feature_flags() #-------------------------------------- # We want to include both the include directory from the source tree and # also the include directory that's generated in the build folder, # ${PROJECT_BINARY_DIR}, so that headers which are generated via cmake will # be visible to the compiler. # # TODO: We should consider removing this include_directories(~) command. # If these directories are needed by any targets, then we should specify it # for those targets directly. if(EXISTS "${PROJECT_SOURCE_DIR}/include") include_directories("${PROJECT_SOURCE_DIR}/include") endif() include_directories("${PROJECT_BINARY_DIR}/include") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/include") #-------------------------------------- # Clear the test results directory # # TODO: This should probably be in a CI script instead of our build # configuration script. execute_process(COMMAND cmake -E remove_directory ${CMAKE_BINARY_DIR}/test_results) execute_process(COMMAND cmake -E make_directory ${CMAKE_BINARY_DIR}/test_results) #-------------------------------------- # Create the "all" meta-target ign_create_all_target() #-------------------------------------- # Add the source code directories of the core library if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/core") # If the directory structure has a subdirectory called "core", we will # use that instead of assuming that src, include, and test subdirectories # exist in the root directory. # # We treat "core" the same way as we treat the component subdirectories. # It's inserted into the beginning of the list to make sure that the core # subdirectory is handled before any other. list(INSERT ign_configure_build_COMPONENTS 0 core) else() add_subdirectory(src) _ign_find_include_script() endif() if(BUILD_TESTING AND EXISTS ${CMAKE_CURRENT_LIST_DIR}/test) add_subdirectory(test) endif() #-------------------------------------- # Add the source, include, and test directories to the cppcheck dirs. # CPPCHECK_DIRS is used in IgnCodeCheck. The variable specifies the # directories static code analyzers should check. Additional directories # are added for each component. set (CPPCHECK_DIRS) set (potential_cppcheck_dirs ${CMAKE_SOURCE_DIR}/src ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/test/integration ${CMAKE_SOURCE_DIR}/test/regression ${CMAKE_SOURCE_DIR}/test/performance) foreach (dir ${potential_cppcheck_dirs}) if (EXISTS ${dir}) list (APPEND CPPCHECK_DIRS ${dir}) endif() endforeach() # Includes for cppcheck. This sets include paths for cppcheck. Additional # directories are added for each component. set (CPPCHECK_INCLUDE_DIRS) set (potential_cppcheck_include_dirs ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/include/${PROJECT_INCLUDE_DIR} ${CMAKE_SOURCE_DIR}/test/integration ${CMAKE_SOURCE_DIR}/test/regression ${CMAKE_SOURCE_DIR}/test/performance) foreach (dir ${potential_cppcheck_include_dirs}) if (EXISTS ${dir}) list (APPEND CPPCHECK_INCLUDE_DIRS ${dir}) endif() endforeach() #-------------------------------------- # Initialize the list of header directories that should be parsed by doxygen if(EXISTS "${CMAKE_SOURCE_DIR}/include") set(ign_doxygen_component_input_dirs "${CMAKE_SOURCE_DIR}/include") else() set(ign_doxygen_component_input_dirs "") endif() #-------------------------------------- # Add the source code directories of each component if they exist foreach(component ${ign_configure_build_COMPONENTS}) if(NOT SKIP_${component} AND NOT INTERNAL_SKIP_${component}) set(found_${component}_src FALSE) # Append the component's include directory to both CPPCHECK_DIRS and # CPPCHECK_INCLUDE_DIRS list(APPEND CPPCHECK_DIRS ${CMAKE_CURRENT_LIST_DIR}/${component}/include) list(APPEND CPPCHECK_INCLUDE_DIRS ${CMAKE_CURRENT_LIST_DIR}/${component}/include) if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${component}/include") # Note: It seems we need to give the delimiter exactly this many # backslashes in order to get a \ plus a newline. This might be # dependent on the implementation of ign_string_append, so be careful # when changing the implementation of that function. ign_string_append(ign_doxygen_component_input_dirs "${CMAKE_CURRENT_LIST_DIR}/${component}/include" DELIM " \\\\\\\\\n ") endif() # Append the component's source directory to CPPCHECK_DIRS. if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${component}/src") list(APPEND CPPCHECK_DIRS ${CMAKE_CURRENT_LIST_DIR}/${component}/src) endif() if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${component}/CMakeLists.txt") # If the component's directory has a top-level CMakeLists.txt, use # that. add_subdirectory(${component}) set(found_${component}_src TRUE) else() # If the component's directory does not have a top-level # CMakeLists.txt, try to call the expected set of subdirectories # individually. This saves us from needing to create very redundant # CMakeLists.txt files that do nothing but redirect us to these # subdirectories. # Add the source files if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/${component}/src/CMakeLists.txt") add_subdirectory(${component}/src) set(found_${component}_src TRUE) endif() _ign_find_include_script(COMPONENT ${component}) # Add the tests if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/${component}/test/CMakeLists.txt") add_subdirectory(${component}/test) endif() endif() if(NOT found_${component}_src) message(AUTHOR_WARNING "Could not find a top-level CMakeLists.txt or src/CMakeLists.txt " "for the component [${component}]!") endif() else() set(skip_msg "Skipping the component [${component}]") if(SKIP_${component}) ign_string_append(skip_msg "by user request") elseif(${component}_MISSING_DEPS) ign_string_append(skip_msg "because the following packages are missing: ${${component}_MISSING_DEPS}") endif() message(STATUS "${skip_msg}") endif() endforeach() #-------------------------------------- # Export the "all" meta-target ign_export_target_all() #-------------------------------------- # Create codecheck target include(IgnCodeCheck) ign_setup_target_for_codecheck() #-------------------------------------- # If we made it this far, the configuration was successful message(STATUS "Build configuration successful") endif() endmacro() macro(ign_set_cxx_feature_flags) set(IGN_KNOWN_CXX_STANDARDS 11 14 17) set(IGN_CXX_11_FEATURES cxx_std_11) set(IGN_CXX_14_FEATURES cxx_std_14) set(IGN_CXX_17_FEATURES cxx_std_17) endmacro() function(_ign_find_include_script) #------------------------------------ # Define the expected arguments set(options) # Unused set(oneValueArgs COMPONENT) set(multiValueArgs) # Unused #------------------------------------ # Parse the arguments cmake_parse_arguments(_ign_find_include_script "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #------------------------------------ # Set the starting point set(include_start "${CMAKE_CURRENT_LIST_DIR}") if(_ign_find_include_script_COMPONENT) ign_string_append(include_start ${_ign_find_include_script_COMPONENT} DELIM "/") endif() # Check each level of depth to find the first CMakeLists.txt. This allows us # to have custom behavior for each include directory structure while also # allowing us to just have one leaf CMakeLists.txt file if a project doesn't # need any custom configuration in its include directories. if(EXISTS "${include_start}/include") if(EXISTS "${include_start}/include/CMakeLists.txt") add_subdirectory("${include_start}/include") elseif(EXISTS "${include_start}/include/ignition/CMakeLists.txt") add_subdirectory("${include_start}/include/ignition") elseif(EXISTS "${include_start}/include/${PROJECT_INCLUDE_DIR}/CMakeLists.txt") add_subdirectory("${include_start}/include/${PROJECT_INCLUDE_DIR}") else() message(AUTHOR_WARNING "You have an include directory [${include_start}/include] without a " "CMakeLists.txt. This means its headers will not get installed!") endif() endif() endfunction() macro(ign_parse_build_type) #============================================================================ # If a build type is not specified, set it to RelWithDebInfo by default if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() # Handle NONE in MSVC as blank and default to RelWithDebInfo if (MSVC AND CMAKE_BUILD_TYPE_UPPERCASE STREQUAL "NONE") set(CMAKE_BUILD_TYPE "RelWithDebInfo") endif() # Convert to uppercase in order to support arbitrary capitalization string(TOUPPER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_UPPERCASE) #============================================================================ # Set variables based on the build type set(BUILD_TYPE_PROFILE FALSE) set(BUILD_TYPE_RELEASE FALSE) set(BUILD_TYPE_RELWITHDEBINFO FALSE) set(BUILD_TYPE_MINSIZEREL FALSE) set(BUILD_TYPE_NONE FALSE) set(BUILD_TYPE_DEBUG FALSE) if("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "DEBUG") set(BUILD_TYPE_DEBUG TRUE) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELEASE") set(BUILD_TYPE_RELEASE TRUE) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "RELWITHDEBINFO") set(BUILD_TYPE_RELWITHDEBINFO TRUE) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "MINSIZEREL") set(BUILD_TYPE_MINSIZEREL TRUE) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "NONE") set(BUILD_TYPE_NONE TRUE) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "COVERAGE") include(IgnCodeCoverage) set(BUILD_TYPE_DEBUG TRUE) ign_setup_target_for_coverage( OUTPUT_NAME coverage TARGET_NAME coverage TEST_RUNNER ctest) ign_setup_target_for_coverage( BRANCH_COVERAGE OUTPUT_NAME coverage-branch TARGET_NAME coverage-branch TEST_RUNNER ctest) elseif("${CMAKE_BUILD_TYPE_UPPERCASE}" STREQUAL "PROFILE") set(BUILD_TYPE_PROFILE TRUE) else() ign_build_error("CMAKE_BUILD_TYPE [${CMAKE_BUILD_TYPE}] unknown. Valid options are: Debug Release RelWithDebInfo MinSizeRel Profile Check") endif() endmacro() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnPython.cmake0000664000175000017500000000166314160533245022423 0ustar jriverojrivero# Copyright 2020 Open Source Robotics Foundation, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Copied from ament/ament_cmake: ament_cmake/ament_cmake_core/cmake/core/python.cmake set(PYTHON_VERSION "" CACHE STRING "Specify specific Python version to use ('major.minor' or 'major')") # if not specified otherwise use Python 3 if(NOT PYTHON_VERSION) set(PYTHON_VERSION "3") endif() find_package(PythonInterp ${PYTHON_VERSION} QUIET) ign-cmake-ignition-cmake2_2.10.0/cmake/ign_auto_headers.hh.in0000664000175000017500000000155014160533245023723 0ustar jriverojrivero/* * Copyright (C) 2017 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ // ****** Do not modify this file. ****** // This file is automatically generated by CMake. Changes should instead be // made to cmake/ign_auto_headers.hh.in in ignition-cmake #include <@PROJECT_INCLUDE_DIR@/config.hh> ${ign_headers} ign-cmake-ignition-cmake2_2.10.0/cmake/FindZIP.cmake0000664000175000017500000000352014160533245021741 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find zip. # # Usage of this module as follows: # # find_package(ZIP) # # Variables defined by this module: # # ZIP_FOUND System has ZIP libs/headers # ZIP_INCLUDE_DIRS The location of ZIP headers # ZIP_LIBRARIES The ZIP libraries include(IgnPkgConfig) ign_pkg_check_modules_quiet(ZIP libzip) # If that failed, then fall back to manual detection. if(NOT ZIP_FOUND) if(NOT ZIP_FIND_QUIETLY) message(STATUS "Attempting manual search for zip") endif() find_path(ZIP_INCLUDE_DIRS zip.h ${ZIP_INCLUDE_DIRS} ENV CPATH) find_library(ZIP_LIBRARIES NAMES zip) set(ZIP_FOUND true) if(NOT ZIP_INCLUDE_DIRS) if(NOT ZIP_FIND_QUIETLY) message(STATUS "Looking for zip headers - not found") endif() set(ZIP_FOUND false) endif() if(NOT ZIP_LIBRARIES) if(NOT ZIP_FIND_QUIETLY) message (STATUS "Looking for zip library - not found") endif() set(ZIP_FOUND false) endif() if(ZIP_FOUND) include(IgnImportTarget) ign_import_target(ZIP) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( ZIP REQUIRED_VARS ZIP_FOUND)ign-cmake-ignition-cmake2_2.10.0/cmake/IgnPackaging.cmake0000664000175000017500000003420114160533245023020 0ustar jriverojrivero#.rst # IgnPackaging # ---------------- # # ign_setup_packages # # Sets up package information for an ignition library project. # # ign_create_package # # Creates a package for an ignition library project # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ################################################# # Set up package information macro(ign_setup_packages) #============================================================================ # Use GNUInstallDirs to get canonical paths. # We use this filesystem style on Windows as well, because (quite frankly) # Windows does not seem to have any sensible convention of its own for # installing development libraries. (If anyone is aware of a widely accepted # convention for where to install development libraries on Windows, please # correct this.) include(GNUInstallDirs) #============================================================================ #Find available package generators # DEB if("${CMAKE_SYSTEM}" MATCHES "Linux") find_program(DPKG_PROGRAM dpkg) if(EXISTS ${DPKG_PROGRAM}) list(APPEND CPACK_GENERATOR "DEB") endif(EXISTS ${DPKG_PROGRAM}) find_program(RPMBUILD_PROGRAM rpmbuild) endif() list(APPEND CPACK_SOURCE_GENERATOR "TBZ2") list(APPEND CPACK_SOURCE_GENERATOR "ZIP") list(APPEND CPACK_SOURCE_IGNORE_FILES "TODO;\.hg/;\.sw.$;/build/;\.hgtags;\.hgignore;appveyor\.yml;\.travis\.yml;codecov\.yml") include(InstallRequiredSystemLibraries) #execute_process(COMMAND dpkg --print-architecture _NPROCE) set(DEBIAN_PACKAGE_DEPENDS "") set(RPM_PACKAGE_DEPENDS "") set(PROJECT_CPACK_CFG_FILE "${PROJECT_BINARY_DIR}/cpack_options.cmake") #============================================================================ # Set CPack variables set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION_FULL}") set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") if(CPACK_GENERATOR) message(STATUS "Found CPack generators: ${CPACK_GENERATOR}") configure_file("${IGNITION_CMAKE_DIR}/cpack_options.cmake.in" ${PROJECT_CPACK_CFG_FILE} @ONLY) set(CPACK_PROJECT_CONFIG_FILE ${PROJECT_CPACK_CFG_FILE}) include(CPack) endif() #============================================================================ # If we're configuring only to package source, stop here if(PACKAGE_SOURCE_ONLY) message(WARNING "Configuration was done in PACKAGE_SOURCE_ONLY mode." "You can build a tarball (make package_source), but nothing else.") return() endif() #============================================================================ # Developer's option to cache PKG_CONFIG_PATH and # LD_LIBRARY_PATH for local installs if(PKG_CONFIG_PATH) set(ENV{PKG_CONFIG_PATH} ${PKG_CONFIG_PATH}:$ENV{PKG_CONFIG_PATH}) endif() if(LD_LIBRARY_PATH) set(ENV{LD_LIBRARY_PATH} ${LD_LIBRARY_PATH}:$ENV{LD_LIBRARY_PATH}) endif() #============================================================================ # Set up installation directories set(IGN_INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}") set(IGN_INCLUDE_INSTALL_DIR_POSTFIX "ignition/${IGN_DESIGNATION}${PROJECT_VERSION_MAJOR}") set(IGN_INCLUDE_INSTALL_DIR_FULL "${IGN_INCLUDE_INSTALL_DIR}/${IGN_INCLUDE_INSTALL_DIR_POSTFIX}") set(IGN_DATA_INSTALL_DIR_POSTFIX "ignition/${PROJECT_NAME_LOWER}") set(IGN_DATA_INSTALL_DIR "${CMAKE_INSTALL_DATAROOTDIR}/${IGN_DATA_INSTALL_DIR_POSTFIX}") set(IGN_LIB_INSTALL_DIR ${CMAKE_INSTALL_LIBDIR}) set(IGN_BIN_INSTALL_DIR ${CMAKE_INSTALL_BINDIR}) #============================================================================ # Handle the user's RPATH setting option(USE_FULL_RPATH "Turn on to enable the full RPATH" OFF) if(USE_FULL_RPATH) # use, i.e. don't skip the full RPATH for the build tree set(CMAKE_SKIP_BUILD_RPATH FALSE) # when building, don't use the install RPATH already # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}") # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if its not a system directory list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${IGN_LIB_INSTALL_DIR}") endif("${isSystemDir}" STREQUAL "-1") endif() #============================================================================ # Add uninstall target configure_file( "${IGNITION_CMAKE_DIR}/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") endmacro() macro(ign_create_packages) #============================================================================ # Load platform-specific build hooks if present. ign_load_build_hooks() #============================================================================ # Tell the user what their settings are message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") endmacro() ################################################# # _ign_create_pkgconfig([COMPONENT ]) # # Provide the name of the target for which we will generate package config info. # If the target is a component, pass in the COMPONENT argument followed by the # component's name. # # NOTE: This will be called automatically by ign_create_core_library(~) and # ign_add_component(~), so users of ignition-cmake should not call this # function. # # NOTE: For ignition-cmake developers, the variables needed by ignition.pc.in or # ignition-component.pc.in MUST be set before calling this function. # # Create a pkgconfig file for your target, and install it. function(_ign_create_pkgconfig) #------------------------------------ # Define the expected arguments set(options) set(oneValueArgs COMPONENT) # Unused set(multiValueArgs) # Unused #------------------------------------ # Parse the arguments cmake_parse_arguments(_ign_create_pkgconfig "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #------------------------------------ # Choose which input file to use if(_ign_create_pkgconfig_COMPONENT) set(pkgconfig_input "${IGNITION_CMAKE_DIR}/pkgconfig/ignition-component.pc.in") set(target_name ${PROJECT_LIBRARY_TARGET_NAME}-${_ign_create_pkgconfig_COMPONENT}) else() set(pkgconfig_input "${IGNITION_CMAKE_DIR}/pkgconfig/ignition.pc.in") set(target_name ${PROJECT_LIBRARY_TARGET_NAME}) endif() set(pkgconfig_output "${CMAKE_BINARY_DIR}/cmake/pkgconfig/${target_name}.pc") set(pkgconfig_install_dir "${IGN_LIB_INSTALL_DIR}/pkgconfig") file(RELATIVE_PATH PC_CONFIG_RELATIVE_PATH_TO_PREFIX "${CMAKE_INSTALL_PREFIX}/${pkgconfig_install_dir}" "${CMAKE_INSTALL_PREFIX}" ) configure_file(${pkgconfig_input} ${pkgconfig_output} @ONLY) install( FILES ${pkgconfig_output} DESTINATION ${pkgconfig_install_dir} COMPONENT pkgconfig) endfunction() ################################################# # _ign_create_cmake_package([COMPONENT ] # [LEGACY_PROJECT_PREFIX ]) # # Provide the name of the target that will be installed and exported. If the # target is a component, pass in the COMPONENT argument followed by the # component's name. # # For packages like sdformat that use inconsistent case in the legacy cmake # variable names (like SDFormat_LIBRARIES), the LEGACY_PROJECT_PREFIX argument # can be used to specify the prefix of these variables. # # NOTE: This will be called automatically by ign_create_core_library(~) and # ign_add_component(~), so users of ignition-cmake should not call this # function. # # NOTE: For ignition-cmake developers, some of the variables needed by # ignition-config.cmake.in or ignition-component-config.cmake.in MUST be # set before calling this function. The following variables are set # automatically by this function: # - import_target_name # - target_output_filename # # Make the cmake config files for this target function(_ign_create_cmake_package) #------------------------------------ # Define the expected arguments set(options ALL) set(oneValueArgs COMPONENT LEGACY_PROJECT_PREFIX) set(multiValueArgs) # Unused #------------------------------------ # Parse the arguments cmake_parse_arguments(_ign_create_cmake_package "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(_ign_create_cmake_package_COMPONENT AND _ign_create_cmake_package_ALL) message(FATAL_ERROR "_ign_create_cmake_package was called with both ALL and COMPONENT " "specified. This is not allowed!") endif() #------------------------------------ # Set configuration arguments if(_ign_create_cmake_package_COMPONENT) set(component ${_ign_create_cmake_package_COMPONENT}) set(target_name ${PROJECT_LIBRARY_TARGET_NAME}-${component}) set(ign_config_input "${IGNITION_CMAKE_DIR}/ignition-component-config.cmake.in") set(simple_import_name ${component}) elseif(_ign_create_cmake_package_ALL) set(ign_config_input "${IGNITION_CMAKE_DIR}/ignition-all-config.cmake.in") set(target_name ${PROJECT_LIBRARY_TARGET_NAME}-all) set(all_pkg_name ${PROJECT_LIBRARY_TARGET_NAME}-all) set(simple_import_name all) else() set(target_name ${PROJECT_LIBRARY_TARGET_NAME}) set(ign_config_input "${IGNITION_CMAKE_DIR}/ignition-config.cmake.in") set(simple_import_name core) endif() if(_ign_create_cmake_package_LEGACY_PROJECT_PREFIX) set(LEGACY_PROJECT_PREFIX ${_ign_create_cmake_package_LEGACY_PROJECT_PREFIX}) else() set(LEGACY_PROJECT_PREFIX ${PROJECT_NAME_NO_VERSION_UPPER}) endif() # This gets used by the ignition-*.config.cmake.in files set(target_output_filename ${target_name}-targets.cmake) set(ign_config_output "${PROJECT_BINARY_DIR}/cmake/${target_name}-config.cmake") set(ign_version_output "${PROJECT_BINARY_DIR}/cmake/${target_name}-config-version.cmake") set(ign_target_ouput "${PROJECT_BINARY_DIR}/cmake/${target_output_filename}") # NOTE: Each component needs to go into its own cmake directory in order to be # found by cmake's native find_package(~) command. set(ign_config_install_dir "${IGN_LIB_INSTALL_DIR}/cmake/${target_name}") set(ign_namespace ${PROJECT_LIBRARY_TARGET_NAME}::) set(import_target_name ${ign_namespace}${target_name}) set(simple_import_name ${ign_namespace}${simple_import_name}) # Configure the package config file. It will be installed to # "[lib]/cmake/ignition-/" where [lib] is the library # installation directory. configure_package_config_file( ${ign_config_input} ${ign_config_output} INSTALL_DESTINATION ${ign_config_install_dir} PATH_VARS IGN_LIB_INSTALL_DIR IGN_INCLUDE_INSTALL_DIR_FULL) # Use write_basic_package_version_file to generate a ConfigVersion file that # allow users of the library to specify the API or version to depend on write_basic_package_version_file( ${ign_version_output} VERSION "${PROJECT_VERSION_FULL_NO_SUFFIX}" COMPATIBILITY SameMajorVersion) # Install the configuration files to the configuration installation directory install( FILES ${ign_config_output} ${ign_version_output} DESTINATION ${ign_config_install_dir} COMPONENT cmake) # Create *-targets.cmake file for build directory export( EXPORT ${target_name} FILE ${ign_target_ouput} # We add a namespace that ends with a :: to the name of the exported target. # This is so consumers of the project can call # find_package(ignition-) # target_link_libraries(consumer_project ignition-::ignition-) # and cmake will understand that the consumer is asking to link the imported # target "ignition-" to their "consumer_project" rather than asking # to link a library named "ignition-". In other words, when # target_link_libraries is given a name that contains double-colons (::) it # will never mistake it for a library name, and it will throw an error if # it cannot find a target with the given name. # # The advantage of linking against a target rather than a library is that # you will automatically link against all the dependencies of that target. # This also helps us create find-config files that are relocatable. NAMESPACE ${ign_namespace}) # Install *-targets.cmake file install( EXPORT ${target_name} DESTINATION ${ign_config_install_dir} FILE ${target_output_filename} # See explanation above for NAMESPACE NAMESPACE ${ign_namespace}) endfunction() ################################################# # Make the cmake config files for this project # Pass an argument to specify the directory where the CMakeLists.txt for the # build hooks is located. If no argument is provided, we default to: # ${PROJECT_SOURCE_DIR}/packager-hooks function(ign_load_build_hooks) if(ARGV0) set(hook_dir ${ARGV0}) else() set(hook_dir "${PROJECT_SOURCE_DIR}/cmake/packager-hooks") endif() if(EXISTS ${hook_dir}/CMakeLists.txt) message(STATUS "Loading packager build hooks from ${hook_dir}") add_subdirectory(${hook_dir}) endif() endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/FindAVCODEC.cmake0000664000175000017500000000212714160533245022345 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find avcodec include(IgnPkgConfig) ign_pkg_check_modules_quiet(AVCODEC libavcodec) if(NOT AVCODEC_FOUND) include(IgnManualSearch) ign_manual_search(AVCODEC HEADER_NAMES "libavcodec/avcodec.h" LIBRARY_NAMES "avcodec") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( AVCODEC REQUIRED_VARS AVCODEC_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnOGRE2.cmake0000664000175000017500000003654514160533245022570 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## #-------------------------------------- # Find OGRE2 headers and libraries # # Usage of this module as follows: # # ign_find_package(IgnOGRE2) # # Variables defined by this module: # # OGRE2_FOUND System has OGRE libs/headers # OGRE2_LIBRARIES The OGRE libraries # OGRE2_INCLUDE_DIRS The location of OGRE headers # OGRE2_VERSION Full OGRE version in the form of MAJOR.MINOR.PATCH # OGRE2_VERSION_MAJOR OGRE major version # OGRE2_VERSION_MINOR OGRE minor version # OGRE2_VERSION_PATCH OGRE patch version # OGRE2_RESOURCE_PATH Path to ogre plugins directory # IgnOGRE2::IgnOGRE2 Imported target for OGRE2 # # On Windows, we assume that all the OGRE* defines are passed in manually # to CMake. # # Supports finding the following OGRE2 components: HlmsPbs, HlmsUnlit, Overlay # # Example usage: # # ign_find_package(IgnOGRE2 # VERSION 2.2.0 # COMPONENTS HlmsPbs HlmsUnlit Overlay) # sanity check if (${IgnOGRE2_FIND_VERSION_MAJOR}) if (${IgnOGRE2_FIND_VERSION_MAJOR} VERSION_LESS "2") set (OGRE2_FOUND false) return() endif() endif() message(STATUS "-- Finding OGRE 2.${IgnOGRE2_FIND_VERSION_MINOR}") set(OGRE2_INSTALL_PATH "OGRE-2.${IgnOGRE2_FIND_VERSION_MINOR}") macro(append_library VAR LIB) if(EXISTS "${LIB}") list(APPEND ${VAR} ${LIB}) endif() endmacro() # filter all ocurrences of LIBRARY_STR with the form of: debug;;optimized; # based on CMAKE_BUILD_TYPE macro(select_lib_by_build_type LIBRARY_STR OUTPUT_VAR) foreach(library ${LIBRARY_STR}) if(library STREQUAL optimized) set(conf optimized) elseif(library STREQUAL debug) set(conf debug) else() if(conf STREQUAL optimized) append_library(LIB_RELEASE ${library}) set(conf) elseif(conf STREQUAL debug) append_library(LIB_DEBUG ${library}) set(conf) else() # assume library without debug/optimized prefix append_library(LIB_RELEASE ${library}) append_library(LIB_DEBUG ${library}) endif() endif() endforeach() if(LIB_DEBUG AND CMAKE_BUILD_TYPE STREQUAL "Debug") set(${OUTPUT_VAR} "${LIB_DEBUG}") elseif(LIB_RELEASE) set(${OUTPUT_VAR} "${LIB_RELEASE}") endif() endmacro() # this macro and the version parsing logic below is taken from the # FindOGRE.cmake file distributed by ogre macro(get_preprocessor_entry CONTENTS KEYWORD VARIABLE) string(REGEX MATCH "# *define +${KEYWORD} +((\"([^\n]*)\")|([^ \n]*))" PREPROC_TEMP_VAR ${${CONTENTS}} ) if (CMAKE_MATCH_3) set(${VARIABLE} ${CMAKE_MATCH_3}) else () set(${VARIABLE} ${CMAKE_MATCH_4}) endif () endmacro() if (NOT WIN32) set(PKG_CONFIG_PATH_ORIGINAL $ENV{PKG_CONFIG_PATH}) # Note: OGRE2 installed from debs is named OGRE-2.2 while the version # installed from source does not have the 2.2 suffix # look for OGRE2 installed from debs ign_pkg_check_modules_quiet(OGRE2 ${OGRE2_INSTALL_PATH} NO_CMAKE_ENVIRONMENT_PATH QUIET) if (OGRE2_FOUND) set(IGN_PKG_NAME ${OGRE2_INSTALL_PATH}) else() # look for OGRE2 installed from source set(PKG_CONFIG_PATH_TMP ${PKG_CONFIG_PATH_ORIGINAL}) execute_process(COMMAND pkg-config --variable pc_path pkg-config OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed) if(_pkgconfig_failed) IGN_BUILD_WARNING ("Failed to get pkg-config search paths") elseif (NOT _pkgconfig_invoke_result STREQUAL "") set (PKG_CONFIG_PATH_TMP "${PKG_CONFIG_PATH_TMP}:${_pkgconfig_invoke_result}") endif() # check and see if there are any paths at all if ("${PKG_CONFIG_PATH_TMP}" STREQUAL "") message("No valid pkg-config search paths found") return() endif() string(REPLACE ":" ";" PKG_CONFIG_PATH_TMP ${PKG_CONFIG_PATH_TMP}) # loop through pkg config paths and find an ogre version that is >= 2.0.0 foreach(pkg_path ${PKG_CONFIG_PATH_TMP}) set(ENV{PKG_CONFIG_PATH} ${pkg_path}) pkg_check_modules(OGRE2 "OGRE" NO_CMAKE_ENVIRONMENT_PATH QUIET) if (OGRE2_FOUND) if (${OGRE2_VERSION} VERSION_LESS 2.0.0) set (OGRE2_FOUND false) else () # pkg_check_modules does not provide complete path to libraries # So update variable to point to full path set(OGRE2_LIBRARY_NAME ${OGRE2_LIBRARIES}) find_library(OGRE2_LIBRARY NAMES ${OGRE2_LIBRARY_NAME} HINTS ${OGRE2_LIBRARY_DIRS} NO_DEFAULT_PATH) if ("${OGRE2_LIBRARY}" STREQUAL "OGRE2_LIBRARY-NOTFOUND") set(OGRE2_FOUND false) continue() else() set(OGRE2_LIBRARIES ${OGRE2_LIBRARY}) endif() set(IGN_PKG_NAME "OGRE") break() endif() endif() endforeach() endif() if (NOT OGRE2_FOUND) return() endif() # use pkg-config to find ogre plugin path # do it here before resetting the pkg-config paths execute_process(COMMAND pkg-config --variable=plugindir ${IGN_PKG_NAME} OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed) if(_pkgconfig_failed) IGN_BUILD_WARNING ("Failed to find OGRE's plugin directory. The build will succeed, but there will likely be run-time errors.") else() set(OGRE2_PLUGINDIR ${_pkgconfig_invoke_result}) endif() # reset pkg config path set(ENV{PKG_CONFIG_PATH} ${PKG_CONFIG_PATH_ORIGINAL}) # verify ogre header can be found in the include path find_path(OGRE2_INCLUDE NAMES Ogre.h PATHS ${OGRE2_INCLUDE_DIRS} NO_DEFAULT_PATH ) if(NOT OGRE2_INCLUDE) set(OGRE2_FOUND false) return() endif() # manually search and append the the RenderSystem/GL3Plus path to # OGRE2_INCLUDE_DIRS so OGRE GL headers can be found foreach (dir ${OGRE2_INCLUDE_DIRS}) get_filename_component(dir_name "${dir}" NAME) if ("${dir_name}" STREQUAL ${IGN_PKG_NAME}) set(dir_include "${dir}/RenderSystems/GL3Plus") else() set(dir_include "${dir}") endif() list(APPEND OGRE2_INCLUDE_DIRS ${dir_include}) endforeach() file(READ ${OGRE2_INCLUDE}/OgrePrerequisites.h OGRE_TEMP_VERSION_CONTENT) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MAJOR OGRE2_VERSION_MAJOR) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MINOR OGRE2_VERSION_MINOR) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_PATCH OGRE2_VERSION_PATCH) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_NAME OGRE2_VERSION_NAME) set(OGRE2_VERSION "${OGRE2_VERSION_MAJOR}.${OGRE2_VERSION_MINOR}.${OGRE2_VERSION_PATCH}") # find ogre components include(IgnImportTarget) foreach(component ${IgnOGRE2_FIND_COMPONENTS}) find_library(OGRE2-${component} NAMES "Ogre${component}_d.${OGRE2_VERSION}" "Ogre${component}_d" "Ogre${component}.${OGRE2_VERSION}" "Ogre${component}" HINTS ${OGRE2_LIBRARY_DIRS}) if (NOT "OGRE2-${component}" STREQUAL "OGRE2-${component}-NOTFOUND") # create a new target for each component set(component_TARGET_NAME "IgnOGRE2-${component}::IgnOGRE2-${component}") set(component_INCLUDE_DIRS ${OGRE2_INCLUDE_DIRS}) # append the Hlms/Common include dir if it exists. string(FIND ${component} "Hlms" HLMS_POS) if(${HLMS_POS} GREATER -1) foreach (dir ${OGRE2_INCLUDE_DIRS}) get_filename_component(dir_name "${dir}" NAME) if ("${dir_name}" STREQUAL ${IGN_PKG_NAME}) set(dir_include "${dir}/Hlms/Common") if (EXISTS ${dir_include}) list(APPEND component_INCLUDE_DIRS ${dir_include}) endif() endif() endforeach() endif() set(component_LIBRARY_DIRS ${OGRE2_LIBRARY_DIRS}) set(component_LIBRARIES ${OGRE2-${component}}) ign_import_target(${component} TARGET_NAME ${component_TARGET_NAME} LIB_VAR component_LIBRARIES INCLUDE_VAR component_INCLUDE_DIRS) # add it to the list of ogre libraries list(APPEND OGRE2_LIBRARIES ${component_TARGET_NAME}) elseif(IgnOGRE2_FIND_REQUIRED_${component}) set(OGRE2_FOUND false) endif() endforeach() if ("${OGRE2_PLUGINDIR}" STREQUAL "") # set path to find ogre plugins # keep variable naming consistent with ogre 1 # TODO currently using harded paths based on dir structure in ubuntu foreach(resource_path ${OGRE2_LIBRARY_DIRS}) list(APPEND OGRE2_RESOURCE_PATH "${resource_path}/OGRE") endforeach() else() set(OGRE2_RESOURCE_PATH ${OGRE2_PLUGINDIR}) # Seems that OGRE2_PLUGINDIR can end in a newline, which will cause problems # when we pass it to the compiler later. string(REPLACE "\n" "" OGRE2_RESOURCE_PATH ${OGRE2_RESOURCE_PATH}) endif() # We need to manually specify the pkgconfig entry (and type of entry), # because ign_pkg_check_modules does not work for it. include(IgnPkgConfig) ign_pkg_config_library_entry(IgnOGRE2 OgreMain) else() #WIN32 set(OGRE2_FOUND TRUE) set(OGRE_LIBRARIES "") set(OGRE2_VERSION "") set(OGRE2_VERSION_MAJOR "") set(OGRE2_VERSION_MINOR "") set(OGRE2_RESOURCE_PATH "") set(OGRE2_SEARCH_VER "OGRE-${IgnOGRE2_FIND_VERSION_MAJOR}.${IgnOGRE2_FIND_VERSION_MINOR}") set(OGRE2_PATHS "") set(OGRE2_INC_PATHS "") foreach(_rootPath ${VCPKG_CMAKE_FIND_ROOT_PATH}) list(APPEND OGRE2_PATHS "${_rootPath}/lib/${OGRE2_SEARCH_VER}/") list(APPEND OGRE2_PATHS "${_rootPath}/lib/${OGRE2_SEARCH_VER}/manual-link/") list(APPEND OGRE2_INC_PATHS "${_rootPath}/include/${OGRE2_SEARCH_VER}") endforeach() find_library(OGRE2_LIBRARY NAMES "OgreMain" HINTS ${OGRE2_PATHS} NO_DEFAULT_PATH) find_path(OGRE2_INCLUDE NAMES "Ogre.h" HINTS ${OGRE2_INC_PATHS}) if("${OGRE2_LIBRARY}" STREQUAL "OGRE2_LIBRARY-NOTFOUND") set(OGRE2_FOUND false) else() set(OGRE2_LIBRARIES ${OGRE2_LIBRARY}) endif() if(NOT OGRE2_INCLUDE) set(OGRE2_FOUND false) endif() if (OGRE2_FOUND) set(OGRE2_INCLUDE_DIRS ${OGRE2_INCLUDE}) set(OGRE2_LIBRARY_DIRS ${OGRE2_PATHS}) file(READ ${OGRE2_INCLUDE}/OgrePrerequisites.h OGRE_TEMP_VERSION_CONTENT) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MAJOR OGRE2_VERSION_MAJOR) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_MINOR OGRE2_VERSION_MINOR) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_PATCH OGRE2_VERSION_PATCH) get_preprocessor_entry(OGRE_TEMP_VERSION_CONTENT OGRE_VERSION_NAME OGRE2_VERSION_NAME) set(OGRE2_VERSION "${OGRE2_VERSION_MAJOR}.${OGRE2_VERSION_MINOR}.${OGRE2_VERSION_PATCH}") set(OGRE_TEMP_VERSION_CONTENT "") macro(ogre_find_component COMPONENT HEADER PATH_HINTS) set(PREFIX OGRE2_${COMPONENT}) find_path(${PREFIX}_INCLUDE_DIR NAMES ${HEADER} HINTS ${OGRE2_INCLUDE_DIRS} PATH_SUFFIXES ${PATH_HINTS} ${COMPONENT} ${OGRE2_SEARCH_VER}/${COMPONENT}) find_library(${PREFIX}_LIBRARY NAMES "Ogre${COMPONENT}" "Ogre${COMPONENT}_d" HINTS ${OGRE2_LIBRARY_DIRS} NO_DEFAULT_PATH) if (NOT ${PREFIX}_FOUND) if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) set(${PREFIX}_FOUND TRUE) set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") endif() endif() endmacro() macro(ogre_find_plugin PLUGIN HEADER) set(PREFIX OGRE2_${PLUGIN}) string(REPLACE "RenderSystem_" "" PLUGIN_TEMP ${PLUGIN}) string(REPLACE "Plugin_" "" PLUGIN_NAME ${PLUGIN_TEMP}) # header files for plugins are not usually needed, but find them anyway if they are present set(OGRE2_PLUGIN_PATH_SUFFIXES PlugIns PlugIns/${PLUGIN_NAME} Plugins Plugins/${PLUGIN_NAME} ${PLUGIN} RenderSystems RenderSystems/${PLUGIN_NAME} ${ARGN}) find_path( ${PREFIX}_INCLUDE_DIR NAMES ${HEADER} HINTS ${OGRE2_INCLUDE_DIRS} ${OGRE_PREFIX_SOURCE} PATH_SUFFIXES ${OGRE2_PLUGIN_PATH_SUFFIXES}) find_library(${PREFIX}_LIBRARY NAMES ${PLUGIN} HINTS ${OGRE2_LIBRARY_DIRS} PATH_SUFFIXES "" opt "${OGRE2_SEARCH_VER}" "${OGRE2_SEARCH_VER}/opt") if (NOT ${PREFIX}_FOUND) if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) set(${PREFIX}_FOUND TRUE) set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") endif() endif() endmacro() ogre_find_component(Overlay OgreOverlaySystem.h "Overlay") ogre_find_component(HlmsPbs OgreHlmsPbs.h Hlms/Pbs/) ogre_find_component(HlmsUnlit OgreHlmsUnlit.h Hlms/Unlit) ogre_find_plugin(Plugin_ParticleFX OgreParticleFXPrerequisites.h PlugIns/ParticleFX/include) ogre_find_plugin(RenderSystem_GL3Plus OgreGL3PlusRenderSystem.h RenderSystems/GL3Plus/include) ogre_find_plugin(RenderSystem_Direct3D11 OgreD3D11RenderSystem.h RenderSystems/Direct3D11/include) foreach(component ${IgnOGRE2_FIND_COMPONENTS}) set(PREFIX OGRE2_${component}) if(${PREFIX}_FOUND) set(component_TARGET_NAME "IgnOGRE2-${component}::IgnOGRE2-${component}") set(component_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS}) # append the Hlms/Common include dir if it exists. string(FIND ${component} "Hlms" HLMS_POS) if(${HLMS_POS} GREATER -1) foreach (dir ${OGRE2_INCLUDE_DIRS}) get_filename_component(dir_name "${dir}" NAME) if ("${dir_name}" STREQUAL "OGRE-${OGRE2_VERSION_MAJOR}.${OGRE2_VERSION_MINOR}") set(dir_include "${dir}/Hlms/Common") if (EXISTS ${dir_include}) list(APPEND component_INCLUDE_DIRS ${dir_include}) endif() endif() endforeach() endif() set(component_LIBRARIES ${${PREFIX}_LIBRARIES}) ign_import_target(${component} TARGET_NAME ${component_TARGET_NAME} LIB_VAR component_LIBRARIES INCLUDE_VAR component_INCLUDE_DIRS ) list(APPEND OGRE2_LIBRARIES ${component_TARGET_NAME}) endif() endforeach() set(OGRE2_PLUGINS_VCPKG Plugin_ParticleFX RenderSystem_GL3Plus RenderSystem_Direct3D11) foreach(PLUGIN ${OGRE2_PLUGINS_VCPKG}) if(OGRE2_${PLUGIN}_FOUND) list(APPEND OGRE2_INCLUDE_DIRS ${OGRE2_${PLUGIN}_INCLUDE_DIRS}) endif() endforeach() endif() endif() set(IgnOGRE2_FOUND false) # create OGRE2 target if (OGRE2_FOUND) set(IgnOGRE2_FOUND true) ign_import_target(IgnOGRE2 TARGET_NAME IgnOGRE2::IgnOGRE2 LIB_VAR OGRE2_LIBRARIES INCLUDE_VAR OGRE2_INCLUDE_DIRS) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnCURL.cmake0000664000175000017500000000401014160533245022475 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find curl. # # Usage of this module as follows: # # find_package(IgnCURL) # # Variables defined by this module: # # curl::curl Imported target for libcurl # # IgnCURL_FOUND System has CURL libs/headers # IgnCURL_INCLUDE_DIRS The location of CURL headers # IgnCURL_LIBRARIES The CURL libraries # IgnCURL_VERSION The version of CURL found set(ign_quiet_arg) if(IgnCURL_FIND_QUIETLY) set(ign_quiet_arg QUIET) endif() find_package(CURL ${IgnCURL_FIND_VERSION} ${ign_quiet_arg}) set(IgnCURL_FOUND ${CURL_FOUND}) if(${IgnCURL_FOUND}) set(IgnCURL_INCLUDE_DIRS ${CURL_INCLUDE_DIRS}) set(IgnCURL_LIBRARIES ${CURL_LIBRARIES}) set(IgnCURL_VERSION ${CURL_VERSION_STRING}) # Older versions of curl don't create imported targets, so we will create # them here if they have not been provided. if(TARGET CURL::libcurl AND NOT TARGET curl::curl) add_library(curl::curl INTERFACE IMPORTED) set_target_properties(curl::curl PROPERTIES INTERFACE_LINK_LIBRARIES CURL::libcurl) endif() include(IgnImportTarget) if(NOT TARGET curl::curl) ign_import_target(curl LIB_VAR CURL_LIBRARIES INCLUDE_VAR CURL_INCLUDE_DIRS) endif() include(IgnPkgConfig) ign_pkg_config_entry(IgnCURL "libcurl >= ${IgnCURL_FIND_VERSION}") endif() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnCMake.cmake0000664000175000017500000000260514160533245022117 0ustar jriverojrivero#.rst # IgnCMake # -------- # # Includes a set of modules that are needed for building the ignition libraries # #=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. #============================================================================ # ignition-cmake modules #============================================================================ include(IgnUtils) include(IgnConfigureProject) include(IgnPackaging) include(IgnCreateDocs) include(IgnSetCompilerFlags) include(IgnConfigureBuild) include(IgnImportTarget) include(IgnPkgConfig) #============================================================================ # Native cmake modules #============================================================================ include(CMakePackageConfigHelpers) include(CMakeParseArguments) ign-cmake-ignition-cmake2_2.10.0/cmake/FindUUID.cmake0000664000175000017500000000461114160533245022047 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find uuid if (UNIX) if(NOT APPLE) include(IgnPkgConfig) ign_pkg_check_modules_quiet(UUID uuid) if(NOT UUID_FOUND) include(IgnManualSearch) ign_manual_search(UUID HEADER_NAMES "uuid.h" LIBRARY_NAMES "uuid libuuid" PATH_SUFFIXES "uuid") endif() # The pkg-config or the manual search will place # /include/uuid in INTERFACE_INCLUDE_DIRECTORIES, # but some projects exepect to use /include, so # we add it as well. # See https://github.com/ignitionrobotics/ign-cmake/issues/103 if(TARGET UUID::UUID) get_property(uuid_include_dirs TARGET UUID::UUID PROPERTY INTERFACE_INCLUDE_DIRECTORIES) set(uuid_include_dirs_extended ${uuid_include_dirs}) foreach(include_dir IN LISTS uuid_include_dirs) if(include_dir MATCHES "uuid$") get_filename_component(include_dir_parent ${include_dir} DIRECTORY) list(APPEND uuid_include_dirs_extended ${include_dir_parent}) endif() endforeach() list(REMOVE_DUPLICATES uuid_include_dirs_extended) set_property( TARGET UUID::UUID PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${uuid_include_dirs_extended}) endif() else() # On Apple platforms the UUID library is provided by the OS SDK # See https://github.com/ignitionrobotics/ign-cmake/issues/127 set(UUID_FOUND TRUE) if(NOT TARGET UUID::UUID) add_library(UUID::UUID INTERFACE IMPORTED) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( UUID REQUIRED_VARS UUID_FOUND) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindEIGEN3.cmake0000664000175000017500000000416714160533245022221 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find EIGEN3 # # Usage of this module is as follows: # # find_package(EIGEN3 [VERSION [.[.]]]) # # Variables defined by this module: # # Eigen3::Eigen Imported target for eigen3 # EIGEN3_FOUND System has eigen3 library and headers find_package(Eigen3 ${EIGEN3_FIND_VERSION} CONFIG) if(EIGEN3_FOUND) # Attempt to create an imported target in case we're using an old version # of Eigen. (This function skip creating the imported target if it already # exists). ign_import_target(EIGEN3 INTERFACE TARGET_NAME Eigen3::Eigen) if(EIGEN3_FIND_VERSION) ign_pkg_config_entry(EIGEN3 "eigen3 >= ${EIGEN3_FIND_VERSION}") else() ign_pkg_config_entry(EIGEN3 "eigen3") endif() return() endif() if(EIGEN3_FIND_VERSION) ign_pkg_check_modules_quiet(EIGEN3 "eigen3 >= ${EIGEN3_FIND_VERSION}" INTERFACE TARGET_NAME Eigen3::Eigen) else() ign_pkg_check_modules_quiet(EIGEN3 "eigen3" INTERFACE TARGET_NAME Eigen3::Eigen) endif() if(MSVC) set(EIGEN3_FOUND TRUE) find_path(EIGEN3_INCLUDE_DIRS signature_of_eigen3_matrix_library) mark_as_advanced(EIGEN3_INCLUDE_DIRS) if(NOT EIGEN3_INCLUDE_DIRS) set(EIGEN3_FOUND FALSE) if(NOT EIGEN3_FIND_QUIETLY) message(STATUS "Looking for eigen headers (signature_of_eigen3_matrix_library) - not found") endif() endif() ign_import_target(EIGEN3 INTERFACE TARGET_NAME Eigen3::Eigen) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindAVFORMAT.cmake0000664000175000017500000000214114160533245022514 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find AV format include(IgnPkgConfig) ign_pkg_check_modules_quiet(AVFORMAT libavformat) if(NOT AVFORMAT_FOUND) include(IgnManualSearch) ign_manual_search(AVFORMAT HEADER_NAMES "libavformat/avformat.h" LIBRARY_NAMES "avformat") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( AVFORMAT REQUIRED_VARS AVFORMAT_FOUND)ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnProtobuf.cmake0000664000175000017500000000762314160533245023545 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find Protobuf # This is an ignition wrapper for finding Protobuf. The purpose of this find # module is to search for a config-file for Protobuf before resorting to using # the native CMake find-module for Protobuf. This ensures that if a specially # configured version of Protobuf is installed, then its exported targets will be # correctly imported. This is especially important on Windows in order to # support shared library versions of Protobuf. include(IgnPkgConfig) ign_pkg_config_entry(IgnProtobuf "protobuf >= ${IgnProtobuf_FIND_VERSION}") find_package(Protobuf ${IgnProtobuf_FIND_VERSION} QUIET CONFIG) if(NOT ${Protobuf_FOUND}) # If a config-file was not found, then fall back on the system-installed # find-module that comes with CMake. find_package(Protobuf ${IgnProtobuf_FIND_VERSION}) endif() set(IgnProtobuf_missing_components "") foreach(component ${IgnProtobuf_FIND_COMPONENTS}) # If specific components are requested, check that each one is accounted for. # If any component is missing, then we should not consider this package to be # found. # If a requested component is not required, then we can just skip this # iteration. We don't do anything special for optional components. if(NOT IgnProtobuf_FIND_REQUIRED_${component}) continue() endif() if((${component} STREQUAL "libprotobuf") OR (${component} STREQUAL "all")) if((NOT PROTOBUF_LIBRARY) AND (NOT TARGET protobuf::libprotobuf)) set(Protobuf_FOUND false) ign_string_append(IgnProtobuf_missing_components "libprotobuf" DELIM " ") endif() endif() if((${component} STREQUAL "libprotoc") OR (${component} STREQUAL "all")) if((NOT PROTOBUF_PROTOC_LIBRARY) AND (NOT TARGET protobuf::libprotoc)) set(Protobuf_FOUND false) ign_string_append(IgnProtobuf_missing_components "libprotoc" DELIM " ") endif() endif() if((${component} STREQUAL "protoc") OR (${component} STREQUAL "all")) if((NOT PROTOBUF_PROTOC_EXECUTABLE) AND (NOT TARGET protobuf::protoc)) set(Protobuf_FOUND false) ign_string_append(IgnProtobuf_missing_components "protoc" DELIM " ") endif() endif() endforeach() if(IgnProtobuf_missing_components AND NOT IgnProtobuf_FIND_QUIETLY) message(STATUS "Missing required protobuf components: ${IgnProtobuf_missing_components}") endif() if(${Protobuf_FOUND}) # If we have found Protobuf, then set the IgnProtobuf_FOUND flag to true so # that ign_find_package(~) knows that we were successful. set(IgnProtobuf_FOUND true) # Older versions of protobuf don't create imported targets, so we will create # them here if they have not been provided. include(IgnImportTarget) if(NOT TARGET protobuf::libprotobuf) ign_import_target(protobuf TARGET_NAME protobuf::libprotobuf LIB_VAR PROTOBUF_LIBRARY INCLUDE_VAR PROTOBUF_INCLUDE_DIR) endif() if(NOT TARGET protobuf::libprotoc) ign_import_target(protobuf TARGET_NAME protobuf::libprotoc LIB_VAR PROTOBUF_PROTOC_LIBRARY INCLUDE_VAR PROTOBUF_INCLUDE_DIR) endif() if(NOT TARGET protobuf::protoc) add_executable(protobuf::protoc IMPORTED) set_target_properties(protobuf::protoc PROPERTIES IMPORTED_LOCATION ${PROTOBUF_PROTOC_EXECUTABLE}) endif() endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindODE.cmake0000664000175000017500000000373614160533245021717 0ustar jriverojrivero#=============================================================================== # Base Io build system # Originally written by there.exists.teslos # Heavily modified by Open Source Robotics Foundation # # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find ODE Open Dynamics Engine find_path(ODE_INCLUDE_DIR ode/ode.h /usr/include /usr/local/include ) set(ODE_NAMES ${ODE_NAMES} ode libode) find_library(ODE_LIBRARIES NAMES ${ODE_NAMES} PATH) if(NOT ODE_FIND_QUIETLY) if(ODE_INCLUDE_DIR) message(STATUS "Found ODE include dir: ${ODE_INCLUDE_DIR}") else(ODE_INCLUDE_DIR) message(STATUS "Couldn't find ODE include dir: ${ODE_INCLUDE_DIR}") endif(ODE_INCLUDE_DIR) if(ODE_LIBRARIES) message(STATUS "Found ODE library: ${ODE_LIBRARIES}") else(ODE_LIBRARIES) message(STATUS "Couldn't find ODE library: ${ODE_LIBRARIES}") endif(ODE_LIBRARIES) endif() if(ODE_INCLUDE_DIR AND ODE_LIBRARIES) set(ODE_FOUND true) endif(ODE_INCLUDE_DIR AND ODE_LIBRARIES) if(ODE_FOUND) if(NOT ODE_FIND_QUIETLY) message(STATUS "Looking for Open Dynamics Engine - found") endif() include(IgnImportTarget) ign_import_target(ODE) if(NOT ODE_FIND_QUIETLY) message(STATUS "Found ODE: ${ODE_LIBRARIES}") endif(NOT ODE_FIND_QUIETLY) endif(ODE_FOUND) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( ODE REQUIRED_VARS ODE_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/IgnPkgConfig.cmake0000664000175000017500000002213414160533245023005 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # An alternative to pkg_check_modules that creates an "imported target" which # helps us to make relocatable packages. # # NOTE: This macro assumes that pkg-config is the only means by which you will # be searching for the package. If you intend to continue searching in the # event that pkg-config fails (or is unavailable), then you should instead # call ign_pkg_check_modules_quiet(~). # # NOTE: If you need to specify a version comparison for pkg-config, then your # second argument must be wrapped in quotes. E.g. if you want to find # version greater than or equal to 3.2.1 of a package called SomePackage # which is known to pkg-config as libsomepackage, then you should call # ign_pkg_check_modules as follows: # # ign_pkg_check_modules(SomePackage "libsomepackage >= 3.2.1") # # The quotes and spaces in the second argument are all very important in # order to ensure that our auto-generated *.pc file gets filled in # correctly. If you do not have any version requirements, then you can # simply leave all of that out: # # ign_pkg_check_modules(SomePackage libsomepackage) # # Without the version comparison, the quotes and spacing are irrelevant. # This usage note applies to ign_pkg_check_modules_quiet(~) as well. # macro(ign_pkg_check_modules package signature) ign_pkg_check_modules_quiet(${package} "${signature}" ${ARGN}) if(NOT PKG_CONFIG_FOUND) message(WARNING "The package [${package}] requires pkg-config in order to be found. " "Please install pkg-config so we can search for that package.") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( ${package} REQUIRED_VARS ${package}_FOUND) endmacro() # This is an alternative to ign_pkg_check_modules(~) which you can use if you # have an alternative way to look for the package if pkg-config is not available # or cannot find the requested package. This will still setup the pkg-config # variables for you, whether or not pkg-config is available. # # For usage instructions, see ign_pkg_check_modules(~) above. macro(ign_pkg_check_modules_quiet package signature) #------------------------------------ # Define the expected arguments set(options INTERFACE NO_CMAKE_ENVIRONMENT_PATH QUIET) set(oneValueArgs "TARGET_NAME") set(multiValueArgs) #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_pkg_check_modules "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ign_pkg_check_modules_INTERFACE) set(_ign_pkg_check_modules_interface_option INTERFACE) else() set(_ign_pkg_check_modules_interface_option) # Intentionally blank endif() if(NOT ign_pkg_check_modules_TARGET_NAME) set(ign_pkg_check_modules_TARGET_NAME "${package}::${package}") endif() find_package(PkgConfig QUIET) ign_pkg_config_entry(${package} "${signature}") if(PKG_CONFIG_FOUND) if(${ign_pkg_check_modules_NO_CMAKE_ENVIRONMENT_PATH}) set(ign_pkg_check_modules_no_cmake_environment_path_arg NO_CMAKE_ENVIRONMENT_PATH) else() set(ign_pkg_check_modules_no_cmake_environment_path_arg) endif() if(${ign_pkg_check_modules_QUIET} OR ${package}_FIND_QUIETLY) set(ign_pkg_check_modules_quiet_arg QUIET) else() set(ign_pkg_check_modules_quiet_arg) endif() pkg_check_modules(${package} ${ign_pkg_check_modules_quiet_arg} ${ign_pkg_check_modules_no_cmake_environment_path_arg} ${signature}) # TODO: When we require cmake-3.6+, we should remove this procedure and just # use the plain pkg_check_modules, which provides an option called # IMPORTED_TARGET that will create the imported targets the way we do # here. if(${package}_FOUND AND NOT TARGET ${ign_pkg_check_modules_TARGET_NAME}) # Because of some idiosyncrasies of pkg-config, pkg_check_modules does not # put /usr/include in the _INCLUDE_DIRS variable. E.g. try running # $ pkg-config --cflags-only-I tinyxml2 # and you'll find that it comes out blank. This blank value gets cached # into the _INCLUDE_DIRS variable even though it's a bad value. If # other packages then try to call find_path(_INCLUDE_DIRS ...) in # their own find-module or config-files, the find_path will quit early # because a CACHE entry exists for _INCLUDE_DIRS. However, that # CACHE entry is blank, and so it will typically be interpreted as a # failed attempt to find the path. So if this _INCLUDE_DIRS # variable is blank, then we'll unset it from the CACHE to avoid # conflicts and confusion. # # TODO(MXG): Consider giving a different prefix (e.g. IGN_PC_${package}) # to pkg_check_modules(~) so that the cached variables don't collide. That # would also help with the next TODO below. if(NOT ${package}_INCLUDE_DIRS) unset(${package}_INCLUDE_DIRS CACHE) endif() # pkg_check_modules will put ${package}_FOUND into the CACHE, which would # prevent our FindXXX.cmake script from being entered the next time cmake # is run by a dependent project. This is a problem for us because we # produce an imported target which gets wiped out and needs to recreated # between runs. # # TODO: Investigate if there is a more conventional solution to this # problem. Perhaps the cmake-3.6 version of pkg_check_modules has a # better solution. unset(${package}_FOUND CACHE) set(${package}_FOUND TRUE) # For some reason, pkg_check_modules does not provide complete paths to the # libraries it returns, even though find_package is conventionally supposed # to provide complete library paths. Having only the library name is harmful # to the ign_create_imported_target macro, so we will change the variable to # give it complete paths. # # TODO: How would we deal with multiple modules that are in different # directories? How does cmake-3.6+ handle that situation? _ign_pkgconfig_find_libraries( ${package}_LIBRARIES ${package} "${${package}_LIBRARIES}" "${${package}_LIBRARY_DIRS}") include(IgnImportTarget) ign_import_target(${package} ${_ign_pkg_check_modules_interface_option} TARGET_NAME ${ign_pkg_check_modules_TARGET_NAME}) endif() endif() endmacro() # This creates variables which inform ign_find_package(~) that your package # should be found as a module by pkg-config. In most cases, this will be called # implicitly by ign_pkg_check_modules[_quiet], but if a package provides both a # cmake config-file (*-config.cmake) and a pkg-config file (*.pc), then you can # use the cmake config-file to retrieve the package information, and then use # this macro to generate the relevant pkg-config information. macro(ign_pkg_config_entry package string) set(${package}_PKGCONFIG_ENTRY "${string}") set(${package}_PKGCONFIG_TYPE PKGCONFIG_REQUIRES) endmacro() # This creates variables which inform ign_find_package(~) that your package must # be found as a plain library by pkg-config. This should be used in any # find-module that handles a library package which does not install a pkg-config # .pc file. macro(ign_pkg_config_library_entry package lib_name) set(${package}_PKGCONFIG_ENTRY "-l${lib_name}") set(${package}_PKGCONFIG_TYPE PKGCONFIG_LIBS) endmacro() # Based on discussion here: https://cmake.org/Bug/view.php?id=15804 # and a patch written by Sam Thursfield function(_ign_pkgconfig_find_libraries output_var package library_names library_dirs) foreach(libname ${library_names}) # As recommended in cmake's find_library documenation, we can call # find_library multiple times with the NO_* option to override search order. # Give priority to path specified by user by telling cmake not to look # in default paths. If the first call succeeds, the second call will not # search again find_library( ${package}_LIBRARY_${libname} ${libname} PATHS ${library_dirs} NO_DEFAULT_PATH) find_library( ${package}_LIBRARY_${libname} ${libname} PATHS ${library_dirs}) mark_as_advanced(${package}_LIBRARY_${libname}) list(APPEND library_paths "${${package}_LIBRARY_${libname}}") endforeach() set(${output_var} ${library_paths} PARENT_SCOPE) endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnCodeCheck.cmake0000664000175000017500000000372014160533245022746 0ustar jriverojrivero# Setup the codecheck target, which will run cppcheck and cppplint. function(ign_setup_target_for_codecheck) include(IgnPython) find_program(CPPCHECK_PATH cppcheck) find_program(FIND_PATH find) if(NOT CPPCHECK_PATH) message(STATUS "The program [cppcheck] was not found! Skipping codecheck setup") return() endif() if(NOT FIND_PATH) message(STATUS "The program [find] was not found! Skipping codecheck setup.") return() endif() # Base set of cppcheck option set (CPPCHECK_BASE -q --inline-suppr -j 4 --language=c++ --std=c++14 --force) if (EXISTS "${PROJECT_BINARY_DIR}/cppcheck.suppress") set (CPPCHECK_BASE ${CPPCHECK_BASE} --suppressions-list=${PROJECT_BINARY_DIR}/cppcheck.suppress) endif() # Extra cppcheck option set (CPPCHECK_EXTRA --enable=style,performance,portability,information) # Rules for cppcheck set (CPPCHECK_RULES "-UM_PI --rule-file=${IGNITION_CMAKE_CODECHECK_DIR}/header_guard.rule --rule-file=${IGNITION_CMAKE_CODECHECK_DIR}/namespace_AZ.rule") # The find command set (CPPCHECK_FIND ${FIND_PATH} ${CPPCHECK_DIRS} -name '*.cc' -o -name '*.hh' -o -name '*.c' -o -name '*.h') message(STATUS "Adding codecheck target") # Each include directory needs an -I flag set(CPPCHECK_INCLUDE_DIRS_FLAGS) foreach(dir ${CPPCHECK_INCLUDE_DIRS}) list(APPEND CPPCHECK_INCLUDE_DIRS_FLAGS "-I${dir}") endforeach() add_custom_target(cppcheck # First cppcheck COMMAND ${CPPCHECK_PATH} ${CPPCHECK_BASE} ${CPPCHECK_EXTRA} ${CPPCHECK_INCLUDE_DIRS_FLAGS} ${CPPCHECK_RULES} `${CPPCHECK_FIND}` # Second cppcheck COMMAND ${CPPCHECK_PATH} ${CPPCHECK_BASE} --enable=missingInclude `${CPPCHECK_FIND}` ) add_custom_target(codecheck DEPENDS cppcheck ) if(PYTHONINTERP_FOUND) add_custom_target(cpplint COMMAND ${PYTHON_EXECUTABLE} ${IGNITION_CMAKE_CODECHECK_DIR}/cpplint.py --extensions=cc,hh --quiet `${CPPCHECK_FIND}` ) add_dependencies(codecheck cpplint) endif() endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/ignition-config.cmake.in0000664000175000017500000001607314160533245024175 0ustar jriverojrivero# - Config file for the @PKG_NAME@ package. # # For finding and loading @PKG_NAME@ from your project, type: # # find_package(@PKG_NAME@) # # This creates the following targets: # # Core library target - @import_target_name@ # Alternative target name - @simple_import_name@ # Core library + all requested components - @ign_namespace@requested # # Use target_link_libraries() to link your library or executable to one of the # above targets. # # We also provide the following variables for backwards compatibility, but use # of these is discouraged: # # @PKG_NAME@_CORE_LIBRARY - Core library (actually contains @simple_import_name@) # @PKG_NAME@_LIBRARIES - All libraries to link against (actually contains @ign_namespace@requested). # @PKG_NAME@_INCLUDE_DIRS - Include directories for @PKG_NAME@ and its dependencies. # # We will also set @PKG_NAME@_FOUND to indicate that the package was found. # ################################################################################ # We explicitly set the desired cmake version to ensure that the policy settings # of users or of toolchains do not result in the wrong behavior for our modules. # Note that the call to find_package(~) will PUSH a new policy stack before # taking on these version settings, and then that stack will POP after the # find_package(~) has exited, so this will not affect the cmake policy settings # of a caller. cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) if(NOT @PKG_NAME@_FIND_QUIETLY) message(STATUS "Looking for @PKG_NAME@ -- found version @PROJECT_VERSION_FULL@") endif() if(@PKG_NAME@_CONFIG_INCLUDED) # Check that each of the components requested in this call to find_package(~) # have already been found. set(@PKG_NAME@_all_requested_components_found true) foreach(component ${@PKG_NAME@_FIND_COMPONENTS}) if(NOT @PKG_NAME@-${component}_FOUND) set(@PKG_NAME@_all_requested_components_found false) break() endif() endforeach() # If this @PKG_NAME@-config.cmake file has been called before, # and all the requested components are already found, then exit early. if(@PKG_NAME@_all_requested_components_found) return() endif() endif() set(@PKG_NAME@_CONFIG_INCLUDED TRUE) # Get access to the find_dependency utility include(CMakeFindDependencyMacro) # Find ignition-cmake, because we need its modules in order to find the rest of # our dependencies. find_dependency(ignition-cmake@IGNITION_CMAKE_VERSION_MAJOR@) # Set the REQUIRED flag for the find_package(~) calls on this project's # dependencies. if(@PKG_NAME@_FIND_REQUIRED) set(ign_package_required REQUIRED) else() set(ign_package_required "") endif() # Set the QUIET flag for the find_package(~) calls on this project's # dependencies. if(@PKG_NAME@_FIND_QUIETLY) set(ign_package_quiet QUIET) else() set(ign_package_quiet "") endif() # -------------------------------- # Find each required dependency of this project (if nothing is below, then the # project has no external dependencies). We use find_package(~) instead of # find_dependency(~) here so that we can support COMPONENT arguments. # # TODO: When we migrate to cmake-3.9+, change these to find_dependency(~), # because at that point the find_dependency(~) function will support # the COMPONENT argument. if(NOT @PKG_NAME@_FIND_QUIETLY) message(STATUS "Searching for dependencies of @PKG_NAME@") endif() @PROJECT_CMAKE_DEPENDENCIES@ # -------------------------------- @PACKAGE_INIT@ if(NOT TARGET @import_target_name@) include("${CMAKE_CURRENT_LIST_DIR}/@target_output_filename@") # Create a simplified imported target name for the core library. # You can link to this target instead of the core library. add_library(@simple_import_name@ INTERFACE IMPORTED) set_target_properties(@simple_import_name@ PROPERTIES INTERFACE_LINK_LIBRARIES @import_target_name@) # Note: In a future version of cmake, we can replace this with an ALIAS target # In case someone tries to link against the plain library name, we want to # intercept that and have them link against a target instead. This is # effectively the same as @simple_import_name@, but it does not have the # benefit of unambiguously being a target name. add_library(@PKG_NAME@ INTERFACE IMPORTED) set_target_properties(@PKG_NAME@ PROPERTIES INTERFACE_LINK_LIBRARIES @import_target_name@) endif() # Create the "all" target if it does not already exist if(NOT TARGET @ign_namespace@requested) add_library(@ign_namespace@requested INTERFACE IMPORTED) endif() # Link the core library to the "all" target. We set the property explicitly # because target_link_libraries cannot be called on an imported target. get_target_property(ign_all_components @ign_namespace@requested INTERFACE_LINK_LIBRARIES) if(NOT ign_all_components) # If @ign_namespace@requested has not been given any libraries yet, then cmake will # set ign_all_components to ign_all_components-NOTFOUND, which is something we # should NOT pass into the INTERFACE_LINK_LIBRARIES property. set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "@import_target_name@") else() set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "${ign_all_components};@import_target_name@") endif() # Package variables. Note that @PKG_NAME@_LIBRARIES and @PKG_NAME@_CORE_LIBRARY # contain imported targets, so @PKG_NAME@_INCLUDE_DIRS is never needed. set(@PKG_NAME@_CORE_LIBRARY @simple_import_name@) set(@PKG_NAME@_LIBRARIES @ign_namespace@requested) set_and_check(@PKG_NAME@_INCLUDE_DIRS "@PACKAGE_IGN_INCLUDE_INSTALL_DIR_FULL@") # Backwards compatibility variables set(@LEGACY_PROJECT_PREFIX@_LIBRARIES ${@PKG_NAME@_LIBRARIES}) set(@LEGACY_PROJECT_PREFIX@_INCLUDE_DIRS ${@PKG_NAME@_INCLUDE_DIRS}) # This macro is used by ignition-cmake to automatically configure the pkgconfig # files for ignition projects. ign_pkg_config_entry(@PKG_NAME@ "@PKG_NAME@") # Find each of the components requested by find_package(~) foreach(component ${@PKG_NAME@_FIND_COMPONENTS}) if(NOT @PKG_NAME@_FIND_QUIETLY) message(STATUS "Searching for <@PKG_NAME@> component [${component}]") endif() if(@PKG_NAME@_FIND_REQUIRED_${component}) # Find the component package using find_dependency(~). If the user specified # REQUIRED or QUIET, those will automatically get forwarded to # find_dependency(~) find_dependency(@PKG_NAME@-${component} @PROJECT_VERSION_FULL_NO_SUFFIX@ EXACT) else() # If this is an optional component, use find_package(~) instead of # find_dependency(~) so we can ensure that the use of REQUIRED does not get # forwarded to it. find_package(@PKG_NAME@-${component} @PROJECT_VERSION_FULL_NO_SUFFIX@ EXACT ${ign_package_quiet}) endif() endforeach() # Specify the doxygen tag file set(@PROJECT_NAME_NO_VERSION_UPPER@_DOXYGEN_TAGFILE "${PACKAGE_PREFIX_DIR}/@IGN_DATA_INSTALL_DIR@/@PROJECT_NAME_LOWER@.tag.xml") # Specify the API url. This is where the doxygen tag file will resolve URLS to. set(@PROJECT_NAME_NO_VERSION_UPPER@_API_URL "https://ignitionrobotics.org/api/@IGN_DESIGNATION@/@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@") ign-cmake-ignition-cmake2_2.10.0/cmake/IgnCodeCoverage.cmake0000664000175000017500000001352114160533245023464 0ustar jriverojrivero# # 2012-01-31, Lars Bilke # - Enable Code Coverage # # 2013-09-17, Joakim Söderberg # - Added support for Clang. # - Some additional usage instructions. # # 2017-09-13 # - Tweaked instructions for ignition libraries # - Tweaked function name to avoid name collisions # # USAGE: # 1. Add the following line to your CMakeLists.txt: # INCLUDE(IgnCodeCoverage) # # 2. Set compiler flags to turn off optimization and enable coverage: # SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") # SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") # # 3. Use the function IGN_SETUP_TARGET_FOR_COVERAGE to create a custom make target # which runs your test executable and produces a lcov code coverage report: # Example: # IGN_SETUP_TARGET_FOR_COVERAGE( # my_coverage_target # Name for custom target. # test_driver # Name of the test driver executable that runs the tests. # # NOTE! This should always have a ZERO as exit code # # otherwise the coverage generation will not complete. # coverage # Name of output directory. # ) # # 4. Build a Coverge build: # cmake -DCMAKE_BUILD_TYPE=Coverage .. # make # make my_coverage_target # # # Check prereqs FIND_PROGRAM( GCOV_PATH gcov ) FIND_PROGRAM( LCOV_PATH lcov ) FIND_PROGRAM( GREP_PATH grep ) FIND_PROGRAM( GENHTML_PATH genhtml ) FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) IF(NOT GCOV_PATH) MESSAGE(FATAL_ERROR "gcov not found! Aborting...") ENDIF() # NOT GCOV_PATH IF(NOT CMAKE_COMPILER_IS_GNUCXX) # Clang version 3.0.0 and greater now supports gcov as well. MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") IF(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") ENDIF() ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX IF ( NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "Coverage")) MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ################################################# # ign_setup_target_for_coverage( # [BRANCH_COVERAGE] # [OUTPUT_NAME ] # [TARGET_NAME ] # [TEST_RUNNER ]) # # This function will create custom coverage targets with the specified options. # # Coverage is not run for files in the following formats: # # *.cxx : We assume these files are created by swig. # moc_*.cpp and qrc_*.cpp : We assume these files are created by Qt's meta-object compiler. # # BRANCH_COVERAGE: Optional. If provided, branch coverage will be computed # instead of line coverage. # # OUTPUT_NAME: Required. # lcov output is generated as _outputname.info # HTML report is generated in _outputname/index.html # # TARGET_NAME: The name of new the custom make target. # # TEST_RUNNER: The name of the target which runs the tests. # MUST return ZERO always, even on errors. # If not, no coverage report will be created! # FUNCTION(ign_setup_target_for_coverage) #------------------------------------ # Define the expected arguments set(options "BRANCH_COVERAGE") set(oneValueArgs "OUTPUT_NAME" "TARGET_NAME" "TEST_RUNNER") set(multiValueArgs) #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(_outputname ${ign_coverage_OUTPUT_NAME}) set(_targetname ${ign_coverage_TARGET_NAME}) set(_testrunner ${ign_coverage_TEST_RUNNER}) if(ign_coverage_BRANCH_COVERAGE) set(_branch_flags --rc lcov_branch_coverage=1) endif() IF(NOT LCOV_PATH) MESSAGE(FATAL_ERROR "lcov not found! Aborting...") ENDIF() # NOT LCOV_PATH IF(NOT GREP_PATH) MESSAGE(FATAL_ERROR "grep not found! Run code coverage on linux or mac.") ENDIF() IF(NOT GENHTML_PATH) MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") ENDIF() # NOT GENHTML_PATH # Setup target ADD_CUSTOM_TARGET(${_targetname} COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info.cleaned ${_outputname}.info # Capturing lcov counters and generating report COMMAND ${LCOV_PATH} ${_branch_flags} -q --no-checksum --directory ${PROJECT_BINARY_DIR} --capture --output-file ${_outputname}.info 2>/dev/null # Remove negative counts COMMAND sed -i '/,-/d' ${_outputname}.info COMMAND ${LCOV_PATH} ${_branch_flags} -q --remove ${_outputname}.info '*/test/*' '/usr/*' '*_TEST*' '*.cxx' 'moc_*.cpp' 'qrc_*.cpp' --output-file ${_outputname}.info.cleaned COMMAND ${GENHTML_PATH} ${_branch_flags} -q --legend -o ${_outputname} ${_outputname}.info.cleaned COMMAND ${LCOV_PATH} --summary ${_outputname}.info.cleaned 2>&1 | grep "lines" | cut -d ' ' -f 4 | cut -d '%' -f 1 > ${_outputname}/lines.txt COMMAND ${LCOV_PATH} --summary ${_outputname}.info.cleaned 2>&1 | grep "functions" | cut -d ' ' -f 4 | cut -d '%' -f 1 > ${_outputname}/functions.txt COMMAND ${LCOV_PATH} ${_branch_flags} --summary ${_outputname}.info.cleaned 2>&1 | grep "branches" | cut -d ' ' -f 4 | cut -d '%' -f 1 > ${_outputname}/branches.txt COMMAND ${CMAKE_COMMAND} -E rename ${_outputname}.info.cleaned ${_outputname}.info WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMENT "Resetting code coverage counters to zero.\n" "Processing code coverage counters and generating report." ) # Show info where to find the report ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD COMMAND COMMAND ${LCOV_PATH} -q --zerocounters --directory ${PROJECT_BINARY_DIR}; COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." ) ENDFUNCTION() # IGN_SETUP_TARGET_FOR_COVERAGE ign-cmake-ignition-cmake2_2.10.0/cmake/IgnManualSearch.cmake0000664000175000017500000000701214160533245023477 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2020 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # ign_manual_search( [INTERFACE] # [HEADER_NAMES ] # [LIBRARY_NAMES ] # [TARGET_NAME ] # [PATH_SUFFIXES ]]) # # This macro will find a library based on the name of one of its headers, # and the library name. # It is used inside Find***.cmake scripts, typicall as fallback for a # ign_pkg_check_modules_quiet call. # It will create an imported target for the library # # INTERFACE: Optional. Use INTERFACE when the target does not actually provide # a library that needs to be linked against (e.g. it is a header-only # library, or the target is just used to specify compiler flags). # # HEADER_NAMES: Optional. Explicitly specify the header names to search with find_path. # Default is .h. # # LIBRARY_NAMES: Optional. Explicitly specify the names of the library to search with find_library. # Default is . # # TARGET_NAME: Optional. Explicitly specify the desired imported target name. # Default is ::. # # PATH_SUFFIXES: Optional. Parameter forwarded to the find_path and find_library calls. # macro(ign_manual_search package) #------------------------------------ # Define the expected arguments set(options INTERFACE) set(oneValueArgs "TARGET_NAME") set(multiValueArgs "HEADER_NAMES" "LIBRARY_NAMES" "PATH_SUFFIXES") #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_manual_search "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ign_manual_search_INTERFACE) set(_ign_manual_search_interface_option INTERFACE) else() set(_ign_manual_search_interface_option) # Intentionally blank endif() if(NOT ign_manual_search_HEADER_NAMES) set(ign_manual_search_HEADER_NAMES "${package}.h") endif() if(NOT ign_manual_search_LIBRARY_NAMES) set(ign_manual_search_LIBRARY_NAMES "${package}") endif() if(NOT ign_manual_search_TARGET_NAME) set(ign_manual_search_TARGET_NAME "${package}::${package}") endif() find_path(${package}_INCLUDE_DIRS NAMES ${ign_manual_search_HEADER_NAMES} PATH_SUFFIXES ${ign_manual_search_PATH_SUFFIXES}) find_library(${package}_LIBRARIES NAMES ${ign_manual_search_LIBRARY_NAMES} PATH_SUFFIXES ${ign_manual_search_PATH_SUFFIXES}) mark_as_advanced(${package}_INCLUDE_DIRS) mark_as_advanced(${package}_LIBRARIES) set(${package}_FOUND true) if(NOT ${package}_INCLUDE_DIRS) set(${package}_FOUND false) endif() if(NOT ${package}_LIBRARIES) set(${package}_FOUND false) endif() if(${package}_FOUND) include(IgnImportTarget) ign_import_target(${package} ${_ign_pkg_check_modules_interface_option} TARGET_NAME ${ign_pkg_check_modules_TARGET_NAME}) endif() endmacro() ign-cmake-ignition-cmake2_2.10.0/cmake/FindOptiX.cmake0000664000175000017500000002160714160533245022350 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Modified from NVIDIA's FindOptiX.cmake distributed in its OptiX SDK # Usage of this module as follows: # # ign_find_package(OptiX) # # Variable used by this module, which needs to be set before calling # find_package: # # OPTIX_INSTALL_DIR Set this variable to the root installation of # OptiX SDK # # Variables defined by this module: # # optix::optix Imported target for optix # optix::optixu Imported target for optixu # optix::optix_prime Imported target for optix_prime # # OptiX_FOUND System has OptiX libs/headers # OptiX_LIBRARIES The OptiX libraries # OptiX_INCLUDE_DIRS The location of OptiX headers # ######################################## # # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of NVIDIA CORPORATION nor the names of its # contributors may be used to endorse or promote products derived # from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY # OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Locate the OptiX distribution. Search in env path first, then look in the system. set(OptiX_INSTALL_DIR "$ENV{OPTIX_INSTALL_DIR}" CACHE PATH "Path to OptiX installed location.") # The distribution contains both 32 and 64 bit libraries. Adjust the library # search path based on the bit-ness of the build. (i.e. 64: bin64, lib64; 32: # bin, lib). Note that on Mac, the OptiX library is a universal binary, so we # only need to look in lib and not lib64 for 64 bit builds. if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT APPLE) set(bit_dest "64") else() set(bit_dest "") endif() # ign-cmake modification: added "ign_" prefix to macro name macro(ign_OPTIX_find_api_library name version) find_library(${name}_LIBRARY NAMES ${name}.${version} ${name} PATHS "${OptiX_INSTALL_DIR}/lib${bit_dest}" NO_DEFAULT_PATH ) find_library(${name}_LIBRARY NAMES ${name}.${version} ${name} ) if(WIN32) find_file(${name}_DLL NAMES ${name}.${version}.dll PATHS "${OptiX_INSTALL_DIR}/bin${bit_dest}" NO_DEFAULT_PATH ) find_file(${name}_DLL NAMES ${name}.${version}.dll ) endif() endmacro() ign_OPTIX_find_api_library(optix 1) ign_OPTIX_find_api_library(optixu 1) ign_OPTIX_find_api_library(optix_prime 1) # Include find_path(OptiX_INCLUDE NAMES optix.h PATHS "${OptiX_INSTALL_DIR}/include" NO_DEFAULT_PATH ) find_path(OptiX_INCLUDE NAMES optix.h ) # Check to make sure we found what we were looking for function(OptiX_report_error error_message required) if(OptiX_FIND_REQUIRED AND required) message(FATAL_ERROR "${error_message}") else() if(NOT OptiX_FIND_QUIETLY) message(STATUS "${error_message}") endif(NOT OptiX_FIND_QUIETLY) endif() endfunction() if(NOT optix_LIBRARY) OptiX_report_error("optix library not found. Please locate before proceeding." TRUE) endif() if(NOT OptiX_INCLUDE) OptiX_report_error("OptiX headers (optix.h and friends) not found. Please locate before proceeding." TRUE) endif() if(NOT optix_prime_LIBRARY) OptiX_report_error("optix Prime library not found. Please locate before proceeding." FALSE) endif() # Macro for setting up dummy targets function(OptiX_add_imported_library name lib_location dll_lib dependent_libs) set(CMAKE_IMPORT_FILE_VERSION 1) # Create imported target # ign-cmake modification: changed to use ${target_name} instead of ${name} set(target_name optix::${name}) add_library(${target_name} SHARED IMPORTED) # Import target "optix" for configuration "Debug" if(WIN32) set_target_properties(${target_name} PROPERTIES IMPORTED_IMPLIB "${lib_location}" #IMPORTED_LINK_INTERFACE_LIBRARIES "glu32;opengl32" IMPORTED_LOCATION "${dll_lib}" IMPORTED_LINK_INTERFACE_LIBRARIES "${dependent_libs}" ) elseif(UNIX) set_target_properties(${target_name} PROPERTIES #IMPORTED_LINK_INTERFACE_LIBRARIES "glu32;opengl32" IMPORTED_LOCATION "${lib_location}" # We don't have versioned filenames for now, and it may not even matter. #IMPORTED_SONAME "${optix_soname}" IMPORTED_LINK_INTERFACE_LIBRARIES "${dependent_libs}" ) else() # Unknown system, but at least try and provide the minimum required # information. set_target_properties(${target_name} PROPERTIES IMPORTED_LOCATION "${lib_location}" IMPORTED_LINK_INTERFACE_LIBRARIES "${dependent_libs}" ) endif() # Commands beyond this point should not need to know the version. set(CMAKE_IMPORT_FILE_VERSION) endfunction() # Sets up a dummy target OptiX_add_imported_library(optix "${optix_LIBRARY}" "${optix_DLL}" "${OPENGL_LIBRARIES}") OptiX_add_imported_library(optixu "${optixu_LIBRARY}" "${optixu_DLL}" "") OptiX_add_imported_library(optix_prime "${optix_prime_LIBRARY}" "${optix_prime_DLL}" "") # ign-cmake modification: added "ign_" prefix to macro name macro(ign_OptiX_check_same_path libA libB) if(_optix_path_to_${libA}) if(NOT _optix_path_to_${libA} STREQUAL _optix_path_to_${libB}) # ${libA} and ${libB} are in different paths. Make sure there isn't a ${libA} next # to the ${libB}. get_filename_component(_optix_name_of_${libA} "${${libA}_LIBRARY}" NAME) if(EXISTS "${_optix_path_to_${libB}}/${_optix_name_of_${libA}}") message(WARNING " ${libA} library found next to ${libB} library that is not being used. Due to the way we are using rpath, the copy of ${libA} next to ${libB} will be used during loading instead of the one you intended. Consider putting the libraries in the same directory or moving ${_optix_path_to_${libB}}/${_optix_name_of_${libA} out of the way.") endif() endif() set( _${libA}_rpath "-Wl,-rpath,${_optix_path_to_${libA}}" ) endif() endmacro() # Since liboptix.1.dylib is built with an install name of @rpath, we need to # compile our samples with the rpath set to where optix exists. if(APPLE) get_filename_component(_optix_path_to_optix "${optix_LIBRARY}" PATH) if(_optix_path_to_optix) set( _optix_rpath "-Wl,-rpath,${_optix_path_to_optix}" ) endif() get_filename_component(_optix_path_to_optixu "${optixu_LIBRARY}" PATH) ign_OptiX_check_same_path(optixu optix) get_filename_component(_optix_path_to_optix_prime "${optix_prime_LIBRARY}" PATH) ign_OptiX_check_same_path(optix_prime optix) ign_OptiX_check_same_path(optix_prime optixu) set( optix_rpath ${_optix_rpath} ${_optixu_rpath} ${_optix_prime_rpath} ) list(LENGTH optix_rpath optix_rpath_LENGTH) if (optix_rpath_LENGTH GREATER 0) list(REMOVE_DUPLICATES optix_rpath) endif() endif() ######################################## if (OptiX_INCLUDE AND optix_LIBRARY) set (OptiX_FOUND TRUE) else() set (OptiX_FOUND FALSE) endif() if (OptiX_FOUND) set(OptiX_INCLUDE_DIRS ${OptiX_INCLUDE}) set(OptiX_LIBRARIES ${optix_LIBRARY} ${optixu_LIBRARY} ${optix_prime_LIBRARY}) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( OptiX REQUIRED_VARS OptiX_FOUND) include(IgnPkgConfig) ign_pkg_config_library_entry(OptiX OptiX) ign-cmake-ignition-cmake2_2.10.0/cmake/IgnUtils.cmake0000664000175000017500000021243414160533245022242 0ustar jriverojrivero ################################################# # ign_find_package( # [REQUIRED] [PRIVATE] [EXACT] [QUIET] [BUILD_ONLY] [PKGCONFIG_IGNORE] # [COMPONENTS ] # [OPTIONAL_COMPONENTS ] # [REQUIRED_BY ] # [PRIVATE_FOR ] # [VERSION ] # [EXTRA_ARGS ] # [PRETTY ] # [PURPOSE <"explanation for this dependency">] # [PKGCONFIG ] # [PKGCONFIG_LIB ] # [PKGCONFIG_VER_COMPARISON < > = <= >= ]) # # This is a wrapper for the standard cmake find_package which behaves according # to the conventions of the ignition library. In particular, we do not quit # immediately when a required package is missing. Instead, we check all # dependencies and provide an overview of what is missing at the end of the # configuration process. Descriptions of the function arguments are as follows: # # : The name of the package as it would normally be passed to # find_package(~). Note if your package corresponds to a # find-module named FindABC.cmake, then must be # ABC, with the case matching. If the find-module is named # FindAbc.cmake, then must be Abc. This will not # necessarily match the library's actual name, nor will it # necessarily match the name used by pkgconfig, so there are # additional arguments (i.e. PRETTY, PKGCONFIG) to specify # alternative names for this package that can be used depending # on the context. # # [REQUIRED]: Optional. If provided, macro will trigger an ignition build_error # when the package cannot be found. If not provided, this macro will # trigger an ignition build_warning when the package is not found. # To specify that something is required by some set of components # (rather than the core library), use REQUIRED_BY. # # [PRIVATE]: Optional. Use this to indicate that consumers of the project do not # need to link against the package, but it must be present on the # system, because our project must link against it. # # [EXACT]: Optional. This will pass on the EXACT option to find_package(~) and # also add it to the call to find_dependency(~) in the # -config.cmake file. # # [QUIET]: Optional. If provided, it will be passed forward to cmake's # find_package(~) command. This macro will still print its normal # output, except there will be no warning if the package is missing, # unless REQUIRED or REQUIRED_BY is specified. # # [BUILD_ONLY]: Optional. Use this to indicate that the project only needs this # package while building, and it does not need to be available to # the consumer of this project at all. Normally this should only # apply to (1) a header-only library whose headers are included # exclusively in the source files and not included in any public # (i.e. installed) project headers, or to (2) a static library # dependency. # # [PKGCONFIG_IGNORE]: Discouraged. If this option is provided, this package will # not be added to the project's pkgconfig file in any way. # This should only be used in very rare circumstances. Note # that BUILD_ONLY will also prevent a pkgconfig entry from # being produced. # # [COMPONENTS]: Optional. If provided, the list that follows it will be passed # to find_package(~) to indicate which components of PACKAGE_NAME # are considered to be dependencies of either this project # (specified by REQUIRED) or this project's components (specified # by REQUIRED_BY). This is effectively the same as the # find_package( ... COMPONENTS ) argument. # # [REQUIRED_BY]: Optional. If provided, the list that follows it must indicate # which library components require the dependency. Note that if # REQUIRED is specified, then REQUIRED_BY does NOT need to be # specified for any components which depend on the core library, # because their dependence on this package will effectively be # inherited from the core library. This will trigger a build # warning to tell the user which component requires this # dependency. # # [PRIVATE_FOR]: Optional. If provided, the list that follows it must indicate # which library components depend on this package privately (i.e. # the package should not be included in its list of interface # libraries). This is only relevant for components that follow # the REQUIRED_BY command. Note that the PRIVATE argument does # not apply to components specified by REQUIRED_BY. This argument # MUST be given for components whose private dependencies have # been specified with REQUIRED_BY. # # [VERSION]: Optional. Follow this argument with the major[.minor[.patch[.tweak]]] # version that you need for this package. # # [EXTRA_ARGS]: Optional. Additional args to pass forward to find_package(~) # # [PRETTY]: Optional. If provided, the string that follows will replace # when printing messages, warnings, or errors to the # terminal. # # [PURPOSE]: Optional. If provided, the string that follows will be appended to # the build_warning or build_error that this function produces when # the package could not be found. # # ========================================================================== # The following arguments pertain to the automatic generation of your # project's pkgconfig file. Ideally, this information should be provided # automatically by ignition-cmake through the cmake find-module that is written # for your dependency. However, if your package gets distributed with its own # cmake config-file or find-module, then it might not automatically set this # information. Therefore, we provide the ability to set it through your call to # ign_find_package(~). These arguments can also be used to overwrite the # pkg-config entries that get generated by the ign-cmake find-module for the # package. Do not hesitate to ask for help if you need to use these arguments. # # [PKGCONFIG]: Optional. If provided, the string that follows will be used to # specify a "required package" for pkgconfig. Note that the option # PKGCONFIG_LIB has higher precedence than this option. # # [PKGCONFIG_LIB]: Optional. Use this to indicate that the package should be # considered a "library" by pkgconfig. This is used for # libraries which do not come with *.pc metadata, such as # system libraries, libm, libdl, or librt. Generally you should # leave this out, because most packages will be considered # "modules" by pkgconfig. The string which follows this # argument will be used as the library name, and the string # that follows a PKGCONFIG argument will be ignored, so the # PKGCONFIG argument can be left out when using this argument. # # [PKGCONFIG_VER_COMPARISON]: Optional. If provided, pkgconfig will be told how # the available version of this package must compare # to the specified version. Acceptable values are # =, <, >, <=, >=. Default will be =. If no version # is provided using VERSION, then this will be left # out, whether or not it is provided. # macro(ign_find_package PACKAGE_NAME) #------------------------------------ # Define the expected arguments set(options REQUIRED PRIVATE EXACT QUIET BUILD_ONLY PKGCONFIG_IGNORE) set(oneValueArgs VERSION PRETTY PURPOSE EXTRA_ARGS PKGCONFIG PKGCONFIG_LIB PKGCONFIG_VER_COMPARISON) set(multiValueArgs REQUIRED_BY PRIVATE_FOR COMPONENTS OPTIONAL_COMPONENTS) #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_find_package "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #------------------------------------ # Construct the arguments to pass to find_package set(${PACKAGE_NAME}_find_package_args ${PACKAGE_NAME}) if(ign_find_package_VERSION) list(APPEND ${PACKAGE_NAME}_find_package_args ${ign_find_package_VERSION}) endif() if(ign_find_package_QUIET) list(APPEND ${PACKAGE_NAME}_find_package_args QUIET) endif() if(ign_find_package_EXACT) list(APPEND ${PACKAGE_NAME}_find_package_args EXACT) endif() if(ign_find_package_COMPONENTS) list(APPEND ${PACKAGE_NAME}_find_package_args COMPONENTS ${ign_find_package_COMPONENTS}) endif() if(ign_find_package_OPTIONAL_COMPONENTS) list(APPEND ${PACKAGE_NAME}_find_package_args OPTIONAL_COMPONENTS ${ign_find_package_OPTIONAL_COMPONENTS}) endif() if(ign_find_package_EXTRA_ARGS) list(APPEND ${PACKAGE_NAME}_find_package_args ${ign_find_package_EXTRA_ARGS}) endif() #------------------------------------ # Figure out which name to print if(ign_find_package_PRETTY) set(${PACKAGE_NAME}_pretty ${ign_find_package_PRETTY}) else() set(${PACKAGE_NAME}_pretty ${PACKAGE_NAME}) endif() #------------------------------------ # Call find_package with the provided arguments find_package(${${PACKAGE_NAME}_find_package_args}) if(${PACKAGE_NAME}_FOUND) message(STATUS "Looking for ${${PACKAGE_NAME}_pretty} - found\n") else() message(STATUS "Looking for ${${PACKAGE_NAME}_pretty} - not found\n") #------------------------------------ # Construct the warning/error message to produce set(${PACKAGE_NAME}_msg "Missing dependency [${${PACKAGE_NAME}_pretty}]") if(ign_find_package_COMPONENTS) ign_list_to_string(comp_str ign_find_package_COMPONENTS DELIM ", ") set(${PACKAGE_NAME}_msg "${${PACKAGE_NAME}_msg} (Components: ${comp_str})") endif() if(DEFINED ign_find_package_PURPOSE) set(${PACKAGE_NAME}_msg "${${PACKAGE_NAME}_msg} - ${ign_find_package_PURPOSE}") endif() #------------------------------------ # If the package is unavailable, tell the user. if(ign_find_package_REQUIRED) # If it was required by the project, we will create an error. ign_build_error(${${PACKAGE_NAME}_msg}) elseif(ign_find_package_REQUIRED_BY) foreach(component ${ign_find_package_REQUIRED_BY}) if(NOT SKIP_${component}) # Otherwise, if it was only required by some of the components, create # a warning about which components will not be available, unless the # user explicitly requested that it be skipped ign_build_warning("Skipping component [${component}]: ${${PACKAGE_NAME}_msg}.\n ^~~~~ Set SKIP_${component}=true in cmake to suppress this warning.\n ") # Create a variable to indicate that we need to skip the component set(INTERNAL_SKIP_${component} true) # Track the missing dependencies ign_string_append(${component}_MISSING_DEPS "${${PACKAGE_NAME}_pretty}" DELIM ", ") endif() endforeach() else() if(NOT ign_find_package_QUIET) ign_build_warning(${${PACKAGE_NAME}_msg}) endif() endif() endif() #------------------------------------ # Add this package to the list of dependencies that will be inserted into the # find-config file, unless the invoker specifies that it should not be added. # Also, add this package or library as an entry to the pkgconfig file that we # will produce for our project. if( ${PACKAGE_NAME}_FOUND AND (ign_find_package_REQUIRED OR ign_find_package_REQUIRED_BY) AND NOT ign_find_package_BUILD_ONLY) # Set up the arguments we want to pass to the find_dependency invokation for # our ignition project. We always need to pass the name of the dependency. # # NOTE: We escape the dollar signs because we want those variable # evaluations to be a part of the string that we produce. It is going # to be put into a *-config.cmake file. Those variables determine # whether the find_package(~) call will be REQUIRED and/or QUIET. # # TODO: When we migrate to cmake-3.9+, this can be removed because calling # find_dependency(~) will automatically forward these properties. set(${PACKAGE_NAME}_dependency_args "${PACKAGE_NAME}") # If a version is provided here, we should pass that as well. if(ign_find_package_VERSION) ign_string_append(${PACKAGE_NAME}_dependency_args ${ign_find_package_VERSION}) endif() # If we have specified the exact version, we should provide that as well. if(ign_find_package_EXACT) ign_string_append(${PACKAGE_NAME}_dependency_args EXACT) endif() # NOTE (MXG): 7 seems to be the number of escapes required to get # "${ign_package_required}" and "${ign_package_quiet}" to show up correctly # as strings in the final config-file outputs. It is unclear to me why the # escapes get collapsed exactly three times, so it is possible that any # changes to this script could cause a different number of escapes to be # necessary. Please use caution when modifying this script. ign_string_append(${PACKAGE_NAME}_dependency_args "\\\\\\\${ign_package_quiet} \\\\\\\${ign_package_required}") # If we have specified components of the dependency, mention those. if(ign_find_package_COMPONENTS) ign_string_append(${PACKAGE_NAME}_dependency_args "COMPONENTS ${ign_find_package_COMPONENTS}") endif() # If there are any additional arguments for the find_package(~) command, # forward them along. if(ign_find_package_EXTRA_ARGS) ign_string_append(${PACKAGE_NAME}_dependency_args "${ign_find_package_EXTRA_ARGS}") endif() # TODO: When we migrate to cmake-3.9+ bring back find_dependency(~) because # at that point it will be able to support COMPONENTS and EXTRA_ARGS # set(${PACKAGE_NAME}_find_dependency "find_dependency(${${PACKAGE_NAME}_dependency_args})") set(${PACKAGE_NAME}_find_dependency "find_package(${${PACKAGE_NAME}_dependency_args})") if(ign_find_package_REQUIRED) # If this is REQUIRED, add it to PROJECT_CMAKE_DEPENDENCIES ign_string_append(PROJECT_CMAKE_DEPENDENCIES "${${PACKAGE_NAME}_find_dependency}" DELIM "\n") endif() if(ign_find_package_REQUIRED_BY) # Identify which components are privately requiring this package foreach(component ${ign_find_package_PRIVATE_FOR}) set(${component}_${PACKAGE_NAME}_PRIVATE true) endforeach() # If this is required by some components, add it to the # ${component}_CMAKE_DEPENDENCIES variables that are specific to those # componenets foreach(component ${ign_find_package_REQUIRED_BY}) if(NOT ${component}_${PACKAGE_NAME}_PRIVATE) ign_string_append(${component}_CMAKE_DEPENDENCIES "${${PACKAGE_NAME}_find_dependency}" DELIM "\n") endif() endforeach() endif() #------------------------------------ # Add this library or project to its relevant pkgconfig entry, unless we # have been explicitly instructed to ignore it. if(NOT ign_find_package_PKGCONFIG_IGNORE) # Here we will set up the pkgconfig entry for this package. Ordinarily, # these variables should be set by the ign-cmake custom find-module for # the package which should use ign_pkg_check_modules[_quiet] or # ign_pkg_config_library_entry. However, that will not be performed by # third-party dependencies that provide their own find-module or their own # cmake config-module. Therefore, we provide the option of specifying # pkgconfig information through the call to ign_find_package. This also # allows callers of ign_find_package(~) to overwrite the default # pkg-config entry that gets generated by the ign-cmake find-modules. # If the caller has specified the arguments PKGCONFIG_LIB or PKGCONFIG, # then we will overwrite these pkgconfig variables with the information # provided by the caller. if(ign_find_package_PKGCONFIG_LIB) # Libraries must be prepended with -l set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "-l${ign_find_package_PKGCONFIG_LIB}") set(${PACKAGE_NAME}_PKGCONFIG_TYPE PKGCONFIG_LIBS) elseif(ign_find_package_PKGCONFIG) # Modules (a.k.a. packages) can just be specified by their package # name without any prefixes like -l set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "${ign_find_package_PKGCONFIG}") set(${PACKAGE_NAME}_PKGCONFIG_TYPE PKGCONFIG_REQUIRES) # Add the version requirements to the entry. if(ign_find_package_VERSION) # Use equivalency by default set(comparison "=") # If the caller has specified a version comparison operator, use that # instead of equivalency. if(ign_find_package_PKGCONFIG_VER_COMPARISON) set(comparison ${ign_find_package_PKGCONFIG_VER_COMPARISON}) endif() # Append the comparison and the version onto the pkgconfig entry set(${PACKAGE_NAME}_PKGCONFIG_ENTRY "${${PACKAGE_NAME}_PKGCONFIG_ENTRY} ${comparison} ${ign_find_package_VERSION}") endif() endif() if(NOT ${PACKAGE_NAME}_PKGCONFIG_ENTRY) # The find-module has not provided a default pkg-config entry for this # package, and the caller of ign_find_package(~) has not explicitly # provided pkg-config information. The caller has also not specified # PKGCONFIG_IGNORE. This means that the requirements of this package # will be unintentionally omitted from the auto-generated # ignition-.pc file. This is probably an oversight in our build # system scripts, so we will emit a warning about this. message(AUTHOR_WARNING " -- THIS MESSAGE IS INTENDED FOR IGNITION-${IGN_DESIGNATION_UPPER} AUTHORS --\n" " (IF YOU SEE THIS, PLEASE REPORT IT)\n" "Could not find pkg-config information for ${PACKAGE_NAME}. " "It was not provided by the find-module for the package, nor was it " "explicitly passed into the call to ign_find_package(~). This is " "most likely an error in this project's use of ign-cmake.") else() # We have pkg-config information for this package if(ign_find_package_REQUIRED) if(ign_find_package_PRIVATE) # If this is a private library or module, use the _PRIVATE suffix set(PROJECT_${PACKAGE_NAME}_PKGCONFIG_TYPE ${${PACKAGE_NAME}_PKGCONFIG_TYPE}_PRIVATE) else() # Otherwise, use the plain type set(PROJECT_${PACKAGE_NAME}_PKGCONFIG_TYPE ${${PACKAGE_NAME}_PKGCONFIG_TYPE}) endif() # Append the entry as a string onto the project-wide variable for # whichever requirement type we selected ign_string_append(PROJECT_${PROJECT_${PACKAGE_NAME}_PKGCONFIG_TYPE} ${${PACKAGE_NAME}_PKGCONFIG_ENTRY}) endif() if(ign_find_package_REQUIRED_BY) # For each of the components that requires this package, append its # entry as a string onto the component-specific variable for whichever # requirement type we selected foreach(component ${ign_find_package_REQUIRED_BY}) if(${component}_${PACKAGE_NAME}_PRIVATE) # If this is a private library or module, use the _PRIVATE suffix set(${component}_${PACKAGE_NAME}_PKGCONFIG_TYPE ${component}_${${PACKAGE_NAME}_PKGCONFIG_TYPE}_PRIVATE) else() # Otherwise, use the plain type set(${component}_${PACKAGE_NAME}_PKGCONFIG_TYPE ${component}_${${PACKAGE_NAME}_PKGCONFIG_TYPE}) endif() # Append the entry as a string onto the component-specific variable # for whichever required type we selected ign_string_append(${${component}_${PACKAGE_NAME}_PKGCONFIG_TYPE} ${${PACKAGE_NAME}_PKGCONFIG_ENTRY}) endforeach() endif() endif() endif() endif() endmacro() ################################################# # ign_string_append( [DELIM ]) # # : The name of the string variable that should be appended to # # : The value that should be appended to the string # # [DELIM]: Specify a delimiter to separate the contents with. Default value is a # space # # Macro to append a value to a string macro(ign_string_append output_var val) #------------------------------------ # Define the expected arguments # NOTE: options cannot be set to PARENT_SCOPE alone, so we put it explicitly # into cmake_parse_arguments(~). We use a semicolon to concatenate it with # this options variable, so all other options should be specified here. set(options) set(oneValueArgs DELIM) set(multiValueArgs) # We are not using multiValueArgs yet #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_string_append "PARENT_SCOPE;${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ign_string_append_DELIM) set(delim "${ign_string_append_DELIM}") else() set(delim " ") endif() if( (NOT ${output_var}) OR (${output_var} STREQUAL "") ) # If ${output_var} is blank, just set it to equal ${val} set(${output_var} "${val}") else() # If ${output_var} already has a value in it, append ${val} with the # delimiter in-between. set(${output_var} "${${output_var}}${delim}${val}") endif() if(ign_string_append_PARENT_SCOPE) set(${output_var} "${${output_var}}" PARENT_SCOPE) endif() endmacro() ################################################# # Macro to turn a list into a string macro(ign_list_to_string _output _input_list) set(${_output}) foreach(_item ${${_input_list}}) # Append each item, and forward any extra options to ign_string_append, such # as DELIM or PARENT_SCOPE ign_string_append(${_output} "${_item}" ${ARGN}) endforeach(_item) endmacro() ################################################# # ign_get_sources_and_unittests( ) # # Grab all the files ending in "*.cc" from either the "src/" subdirectory or the # current subdirectory if "src/" does not exist. They will be collated into # library source files and unittest source files . # # These output variables can be consumed directly by ign_create_core_library(~), # ign_add_component(~), ign_build_tests(~), and ign_build_executables(~). function(ign_get_libsources_and_unittests lib_sources_var tests_var) # Glob all the source files if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/src) # Prefer files in the src/ subdirectory file(GLOB source_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "src/*.cc") file(GLOB test_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "src/*_TEST.cc") else() # If src/ doesn't exist, then use the current directory file(GLOB source_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "*.cc") file(GLOB test_files RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "*_TEST.cc") endif() # Sort the files alphabetically if(source_files) list(SORT source_files) endif() if(test_files) list(SORT test_files) endif() # Initialize the test list set(tests) # Remove the unit tests from the list of source files foreach(test_file ${test_files}) # Remove from the source_files list. list(REMOVE_ITEM source_files ${test_file}) # Append to the list of tests. list(APPEND tests ${test_file}) endforeach() # Return the lists that have been created. set(${lib_sources_var} ${source_files} PARENT_SCOPE) set(${tests_var} ${tests} PARENT_SCOPE) endfunction() ################################################# # ign_get_sources() # # From the current directory, grab all the source files and place them into # . Remove their paths to make them suitable for passing into # ign_add_[library/tests]. function(ign_get_sources sources_var) # GLOB all the source files file(GLOB source_files "*.cc") list(SORT source_files) # Initialize this list set(sources) foreach(source_file ${source_files}) # Remove the path from the source file and append it the list of soures get_filename_component(source ${source_file} NAME) list(APPEND sources ${source}) endforeach() # Return the list that has been created set(${sources_var} ${sources} PARENT_SCOPE) endfunction() ################################################# # ign_install_all_headers( # [EXCLUDE_FILES ] # [EXCLUDE_DIRS ] # [GENERATED_HEADERS ] # [COMPONENT] ) # # From the current directory, install all header files, including files from all # subdirectories (recursively). You can optionally specify directories or files # to exclude from installation (the names must be provided relative to the current # source directory). # # This will accept all files ending in *.h and *.hh. You may append an # additional suffix (like .old or .backup) to prevent a file from being included. # # GENERATED_HEADERS should be generated headers which should be included by # ${IGN_DESIGNATION}.hh. This will only add them to the header, it will not # generate or install them. # # This will also run configure_file on ign_auto_headers.hh.in and config.hh.in # and install them. This will NOT install any other files or directories that # appear in the ${CMAKE_CURRENT_BINARY_DIR}. # # If the COMPONENT option is specified, this will skip over configuring a # config.hh file since it would be redundant with the core library. # function(ign_install_all_headers) #------------------------------------ # Define the expected arguments set(options) set(oneValueArgs COMPONENT) # We are not using oneValueArgs yet set(multiValueArgs EXCLUDE_FILES EXCLUDE_DIRS GENERATED_HEADERS) #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_install_all_headers "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) #------------------------------------ # Build the list of directories file(GLOB_RECURSE all_files LIST_DIRECTORIES TRUE RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*") list(SORT all_files) set(directories) foreach(f ${all_files}) # Check if this file is a directory if(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${f}) # Check if it is in the list of excluded directories list(FIND ign_install_all_headers_EXCLUDE_DIRS ${f} f_index) set(append_file TRUE) foreach(subdir ${ign_install_all_headers_EXCLUDE_DIRS}) # Check if ${f} contains ${subdir} as a substring string(FIND ${f} ${subdir} pos) # If ${subdir} is a substring of ${f} at the very first position, then # we should not include anything from this directory. This makes sure # that if a user specifies "EXCLUDE_DIRS foo" we will also exclude # the directories "foo/bar/..." and so on. We will not, however, exclude # a directory named "bar/foo/". if(${pos} EQUAL 0) set(append_file FALSE) break() endif() endforeach() if(append_file) list(APPEND directories ${f}) endif() endif() endforeach() # Append the current directory to the list list(APPEND directories ".") #------------------------------------ # Install all the non-excluded header directories along with all of their # non-excluded headers foreach(dir ${directories}) # GLOB all the header files in dir file(GLOB headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${dir}/*.h" "${dir}/*.hh" "${dir}/*.hpp") list(SORT headers) # Remove the excluded headers if(headers) foreach(exclude ${ign_install_all_headers_EXCLUDE_FILES}) list(REMOVE_ITEM headers ${exclude}) endforeach() endif() # Add each header, prefixed by its directory, to the auto headers variable foreach(header ${headers}) set(ign_headers "${ign_headers}#include <${PROJECT_INCLUDE_DIR}/${header}>\n") endforeach() if("." STREQUAL ${dir}) set(destination "${IGN_INCLUDE_INSTALL_DIR_FULL}/${PROJECT_INCLUDE_DIR}") else() set(destination "${IGN_INCLUDE_INSTALL_DIR_FULL}/${PROJECT_INCLUDE_DIR}/${dir}") endif() install( FILES ${headers} DESTINATION ${destination} COMPONENT headers) endforeach() # Add generated headers to the list of includes foreach(header ${ign_install_all_headers_GENERATED_HEADERS}) set(ign_headers "${ign_headers}#include <${PROJECT_INCLUDE_DIR}/${header}>\n") endforeach() if(ign_install_all_headers_COMPONENT) set(component_name ${ign_install_all_headers_COMPONENT}) # Define the install directory for the component meta header set(meta_header_install_dir ${IGN_INCLUDE_INSTALL_DIR_FULL}/${PROJECT_INCLUDE_DIR}/${component_name}) # Define the input/output of the configuration for the component "master" header set(master_header_in ${IGNITION_CMAKE_DIR}/ign_auto_headers.hh.in) set(master_header_out ${CMAKE_CURRENT_BINARY_DIR}/${component_name}.hh) else() # Define the install directory for the core master meta header set(meta_header_install_dir ${IGN_INCLUDE_INSTALL_DIR_FULL}/${PROJECT_INCLUDE_DIR}) # Define the input/output of the configuration for the core "master" header set(master_header_in ${IGNITION_CMAKE_DIR}/ign_auto_headers.hh.in) set(master_header_out ${CMAKE_CURRENT_BINARY_DIR}/../${IGN_DESIGNATION}.hh) endif() # Generate the "master" header that includes all of the headers configure_file(${master_header_in} ${master_header_out}) # Install the "master" header install( FILES ${master_header_out} DESTINATION ${meta_header_install_dir}/.. COMPONENT headers) # Define the input/output of the configuration for the "config" header set(config_header_in ${CMAKE_CURRENT_SOURCE_DIR}/config.hh.in) set(config_header_out ${CMAKE_CURRENT_BINARY_DIR}/config.hh) if(NOT ign_install_all_headers_COMPONENT) # Produce an error if the config file is missing # # TODO: Maybe we should have a generic config.hh.in file that we fall back # on if the project does not have one for itself? if(NOT EXISTS ${config_header_in}) message(FATAL_ERROR "Developer error: You are missing the file [${config_header_in}]! " "Did you forget to move it from your project's cmake directory while " "migrating to the use of ignition-cmake?") endif() # Generate the "config" header that describes our project configuration configure_file(${config_header_in} ${config_header_out}) # Install the "config" header install( FILES ${config_header_out} DESTINATION ${meta_header_install_dir} COMPONENT headers) endif() endfunction() ################################################# # ign_build_error macro macro(ign_build_error) foreach(str ${ARGN}) set(msg "\t${str}") list(APPEND build_errors ${msg}) endforeach() endmacro(ign_build_error) ################################################# # ign_build_warning macro macro(ign_build_warning) foreach(str ${ARGN}) list(APPEND build_warnings "${str}") endforeach(str ${ARGN}) endmacro(ign_build_warning) ################################################# macro(ign_add_library lib_target_name) message(FATAL_ERROR "ign_add_library( ) is deprecated. Instead, use " "ign_create_core_library(SOURCES ). It will determine the library " "target name automatically from the project name. To add a component " "library, use ign_add_component(~). Be sure to pass the CXX_STANDARD " "argument to these functions in order to set the C++ standard that they " "require.") ign_create_core_library(SOURCES ${ARGN}) endmacro() ################################################# # _ign_check_known_cxx_standards(<11|14|17>) # # Creates a fatal error if the variable passed in does not represent a supported # version of the C++ standard. # # NOTE: This function is meant for internal ign-cmake use # function(_ign_check_known_cxx_standards standard) list(FIND IGN_KNOWN_CXX_STANDARDS ${standard} known) if(${known} EQUAL -1) message(FATAL_ERROR "You have specified an unsupported standard: ${standard}. " "Accepted values are: ${IGN_KNOWN_CXX_STANDARDS}.") endif() endfunction() ################################################# # _ign_handle_cxx_standard( # # ) # # Handles the C++ standard argument for ign_create_core_library(~) and # ign_add_component(~). # # NOTE: This is only meant for internal ign-cmake use. # macro(_ign_handle_cxx_standard prefix target pkgconfig_cflags) if(${prefix}_CXX_STANDARD) _ign_check_known_cxx_standards(${${prefix}_CXX_STANDARD}) endif() if(${prefix}_PRIVATE_CXX_STANDARD) _ign_check_known_cxx_standards(${${prefix}_PRIVATE_CXX_STANDARD}) endif() if(${prefix}_INTERFACE_CXX_STANDARD) _ign_check_known_cxx_standards(${${prefix}_INTERFACE_CXX_STANDARD}) endif() if(${prefix}_CXX_STANDARD AND (${prefix}_PRIVATE_CXX_STANDARD OR ${prefix}_INTERFACE_CXX_STANDARD)) message(FATAL_ERROR "If CXX_STANDARD has been specified, then you are not allowed to specify " "PRIVATE_CXX_STANDARD or INTERFACE_CXX_STANDARD. Please choose to either " "specify CXX_STANDARD alone, or else specify some combination of " "PRIVATE_CXX_STANDARD and INTERFACE_CXX_STANDARD") endif() if(${prefix}_CXX_STANDARD) set(${prefix}_INTERFACE_CXX_STANDARD ${${prefix}_CXX_STANDARD}) set(${prefix}_PRIVATE_CXX_STANDARD ${${prefix}_CXX_STANDARD}) endif() if(${prefix}_INTERFACE_CXX_STANDARD) target_compile_features(${target} INTERFACE ${IGN_CXX_${${prefix}_INTERFACE_CXX_STANDARD}_FEATURES}) ign_string_append(${pkgconfig_cflags} "-std=c++${${prefix}_INTERFACE_CXX_STANDARD}") endif() if(${prefix}_PRIVATE_CXX_STANDARD) target_compile_features(${target} PRIVATE ${IGN_CXX_${${prefix}_PRIVATE_CXX_STANDARD}_FEATURES}) endif() endmacro() ################################################# # ign_create_core_library(SOURCES # [CXX_STANDARD <11|14|17>] # [PRIVATE_CXX_STANDARD <11|14|17>] # [INTERFACE_CXX_STANDARD <11|14|17>] # [GET_TARGET_NAME ] # [LEGACY_PROJECT_PREFIX ]) # # This function will produce the "core" library for your project. There is no # need to specify a name for the library, because that will be determined by # your project information. # # SOURCES: Required. Specify the source files that will be used to generate the # library. # # [GET_TARGET_NAME]: Optional. The variable that follows this argument will be # set to the library target name that gets produced by this # function. The target name will always be # ${PROJECT_LIBRARY_TARGET_NAME}. # # [LEGACY_PROJECT_PREFIX]: Optional. The variable that follows this argument will be # used as a prefix for the legacy cmake config variables # _LIBRARIES and _INCLUDE_DIRS. # # If you need a specific C++ standard, you must also specify it in this # function in order to ensure that your library's target properties get set # correctly. The following is a breakdown of your choices: # # [CXX_STANDARD]: This library must compile using the specified standard, and so # must any libraries which link to it. # # [PRIVATE_CXX_STANDARD]: This library must compile using the specified standard, # but libraries which link to it do not need to. # # [INTERFACE_CXX_STANDARD]: Any libraries which link to this library must compile # with the specified standard. # # Most often, you will want to use CXX_STANDARD, but there may be cases in which # you want a finer degree of control. If your library must compile with a # different standard than what is required by dependent libraries, then you can # specify both PRIVATE_CXX_STANDARD and INTERFACE_CXX_STANDARD without any # conflict. However, both of those arguments conflict with CXX_STANDARD, so you # are not allowed to use either of them if you use the CXX_STANDARD argument. # function(ign_create_core_library) #------------------------------------ # Define the expected arguments set(options INTERFACE) set(oneValueArgs INCLUDE_SUBDIR LEGACY_PROJECT_PREFIX CXX_STANDARD PRIVATE_CXX_STANDARD INTERFACE_CXX_STANDARD GET_TARGET_NAME) set(multiValueArgs SOURCES) #------------------------------------ # Parse the arguments cmake_parse_arguments(ign_create_core_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ign_create_core_library_SOURCES) set(sources ${ign_create_core_library_SOURCES}) elseif(NOT ign_create_core_library_INTERFACE) message(FATAL_ERROR "You must specify SOURCES for ign_create_core_library(~)!") endif() if(ign_create_core_library_INTERFACE) set(interface_option INTERFACE) set(property_type INTERFACE) else() set(interface_option) # Intentionally blank set(property_type PUBLIC) endif() #------------------------------------ # Create the target for the core library, and configure it to be installed _ign_add_library_or_component( LIB_NAME ${PROJECT_LIBRARY_TARGET_NAME} INCLUDE_DIR "${PROJECT_INCLUDE_DIR}" EXPORT_BASE IGNITION_${IGN_DESIGNATION_UPPER} SOURCES ${sources} ${interface_option}) # These generator expressions are necessary for multi-configuration generators # such as MSVC on Windows. They also ensure that our target exports its # headers correctly target_include_directories(${PROJECT_LIBRARY_TARGET_NAME} ${property_type} # This is the publicly installed headers directory. "$" # This is the in-build version of the core library headers directory. # Generated headers for the core library get placed here. "$" # Generated headers for the core library might also get placed here. "$") # We explicitly create these directories to avoid false-flag compiler warnings file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/include" "${PROJECT_BINARY_DIR}/core/include") if(EXISTS "${PROJECT_SOURCE_DIR}/include") target_include_directories(${PROJECT_LIBRARY_TARGET_NAME} ${property_type} # This is the build directory version of the headers. When exporting the # target, this will not be included, because it is tied to the build # interface instead of the install interface. "$") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/core/include") target_include_directories(${PROJECT_LIBRARY_TARGET_NAME} ${property_type} # This is the include directories for projects that put the core library # contents into its own subdirectory. "$") endif() #------------------------------------ # Adjust variables if a specific C++ standard was requested _ign_handle_cxx_standard(ign_create_core_library ${PROJECT_LIBRARY_TARGET_NAME} PROJECT_PKGCONFIG_CFLAGS) #------------------------------------ # Handle cmake and pkgconfig packaging if(ign_create_core_library_INTERFACE) set(project_pkgconfig_core_lib) # Intentionally blank else() set(project_pkgconfig_core_lib "-l${PROJECT_NAME_LOWER}") endif() # Export and install the core library's cmake target and package information _ign_create_cmake_package(LEGACY_PROJECT_PREFIX ${ign_create_core_library_LEGACY_PROJECT_PREFIX}) # Generate and install the core library's pkgconfig information _ign_create_pkgconfig() #------------------------------------ # Pass back the target name if they ask for it. if(ign_create_core_library_GET_TARGET_NAME) set(${ign_create_core_library_GET_TARGET_NAME} ${PROJECT_LIBRARY_TARGET_NAME} PARENT_SCOPE) endif() endfunction() ################################################# # ign_add_component( # SOURCES | INTERFACE # [DEPENDS_ON_COMPONENTS ] # [INCLUDE_SUBDIR ] # [GET_TARGET_NAME ] # [INDEPENDENT_FROM_PROJECT_LIB] # [PRIVATELY_DEPENDS_ON_PROJECT_LIB] # [INTERFACE_DEPENDS_ON_PROJECT_LIB] # [CXX_STANDARD <11|14|17>] # [PRIVATE_CXX_STANDARD <11|14|17>] # [INTERFACE_CXX_STANDARD <11|14|17>]) # # This function will produce a "component" library for your project. This is the # recommended way to produce plugins or library modules. # # : Required. Name of the component. The final name of this library # and its target will be ignition-- # # SOURCES: Required (unless INTERFACE is specified). Specify the source files # that will be used to generate the library. # # INTERFACE: Indicate that this is an INTERFACE library which does not require # any source files. This is required if SOURCES is not specified. # # [DEPENDS_ON_COMPONENTS]: Specify a list of other components of this package # that this component depends on. This argument should # be considered mandatory whenever there are # inter-component dependencies in an ignition package. # # [INCLUDE_SUBDIR]: Optional. If specified, the public include headers for this # component will go into "ignition///". # If not specified, they will go into "ignition///" # # [GET_TARGET_NAME]: Optional. The variable that follows this argument will be # set to the library target name that gets produced by this # function. The target name will always be # ${PROJECT_LIBRARY_TARGET_NAME}-. # # [INDEPENDENT_FROM_PROJECT_LIB]: # Optional. Specify this if you do NOT want this component to automatically # be linked to the core library of this project. The default behavior is to # be publically linked. # # [PRIVATELY_DEPENDS_ON_PROJECT_LIB]: # Optional. Specify this if this component privately depends on the core # library of this project (i.e. users of this component do not need to # interface with the core library). The default behavior is to be publicly # linked. # # [INTERFACE_DEPENDS_ON_PROJECT_LIB]: # Optional. Specify this if the component's interface depends on the core # library of this project (i.e. users of this component need to interface # with the core library), but the component itself does not need to link to # the core library. # # See the documentation of ign_create_core_library(~) for more information about # specifying the C++ standard. If your component publicly depends on the core # library, then you probably do not need to specify the standard, because it # will get inherited from the core library. function(ign_add_component component_name) #------------------------------------ # Define the expected arguments set(options INTERFACE INDEPENDENT_FROM_PROJECT_LIB PRIVATELY_DEPENDS_ON_PROJECT_LIB INTERFACE_DEPENDS_ON_PROJECT_LIB) set(oneValueArgs INCLUDE_SUBDIR GET_TARGET_NAME) set(multiValueArgs SOURCES DEPENDS_ON_COMPONENTS) #------------------------------------ # Parse the arguments cmake_parse_arguments(ign_add_component "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(POLICY CMP0079) cmake_policy(SET CMP0079 NEW) endif() if(ign_add_component_SOURCES) set(sources ${ign_add_component_SOURCES}) elseif(NOT ign_add_component_INTERFACE) message(FATAL_ERROR "You must specify SOURCES for ign_add_component(~)!") endif() if(ign_add_component_INCLUDE_SUBDIR) set(include_subdir ${ign_add_component_INCLUDE_SUBDIR}) else() set(include_subdir ${component_name}) endif() if(ign_add_component_INTERFACE) set(interface_option INTERFACE) set(property_type INTERFACE) else() set(interface_option) # Intentionally blank set(property_type PUBLIC) endif() # Set the name of the component's target set(component_target_name ${PROJECT_LIBRARY_TARGET_NAME}-${component_name}) # Pass the component's target name back to the caller if requested if(ign_add_component_GET_TARGET_NAME) set(${ign_add_component_GET_TARGET_NAME} ${component_target_name} PARENT_SCOPE) endif() # Create an upper case version of the component name, to be used as an export # base name. string(TOUPPER ${component_name} component_name_upper) # hyphen is not supported as macro name, replace it by underscore string(REPLACE "-" "_" component_name_upper ${component_name_upper}) #------------------------------------ # Create the target for this component, and configure it to be installed _ign_add_library_or_component( LIB_NAME ${component_target_name} INCLUDE_DIR "${PROJECT_INCLUDE_DIR}/${include_subdir}" EXPORT_BASE IGNITION_${IGN_DESIGNATION_UPPER}_${component_name_upper} SOURCES ${sources} ${interface_option}) if(ign_add_component_INDEPENDENT_FROM_PROJECT_LIB OR ign_add_component_PRIVATELY_DEPENDS_ON_PROJECT_LIB) # If we are not linking this component to the core library, then we need to # add these include directories to this component library directly. This is # not needed if we link to the core library, because that will pull in these # include directories automatically. target_include_directories(${component_target_name} ${property_type} # This is the publicly installed ignition/math headers directory. "$" # This is the in-build version of the core library's headers directory. # Generated headers for this component might get placed here, even if # the component is independent of the core library. "$") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/include") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/${component_name}/include") target_include_directories(${component_target_name} ${property_type} # This is the in-source version of the component-specific headers # directory. When exporting the target, this will not be included, # because it is tied to the build interface instead of the install # interface. "$") endif() target_include_directories(${component_target_name} ${property_type} # This is the in-build version of the component-specific headers # directory. Generated headers for this component might end up here. "$") file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/${component_name}/include") #------------------------------------ # Adjust variables if a specific C++ standard was requested _ign_handle_cxx_standard(ign_add_component ${component_target_name} ${component_name}_PKGCONFIG_CFLAGS) #------------------------------------ # Adjust the packaging variables based on how this component depends (or not) # on the core library. if(ign_add_component_PRIVATELY_DEPENDS_ON_PROJECT_LIB) target_link_libraries(${component_target_name} PRIVATE ${PROJECT_LIBRARY_TARGET_NAME}) endif() if(ign_add_component_INTERFACE_DEPENDS_ON_PROJECT_LIB) target_link_libraries(${component_target_name} INTERFACE ${PROJECT_LIBRARY_TARGET_NAME}) endif() if(NOT ign_add_component_INDEPENDENT_FROM_PROJECT_LIB AND NOT ign_add_component_PRIVATELY_DEPENDS_ON_PROJECT_LIB AND NOT ign_add_component_INTERFACE_DEPENDS_ON_PROJECT_LIB) target_link_libraries(${component_target_name} ${property_type} ${PROJECT_LIBRARY_TARGET_NAME}) endif() if(NOT ign_add_component_INDEPENDENT_FROM_PROJECT_LIB) # Add the core library as a cmake dependency for this component # NOTE: It seems we need to triple-escape "${ign_package_required}" and # "${ign_package_quiet}" here. ign_string_append(${component_name}_CMAKE_DEPENDENCIES "if(NOT ${PKG_NAME}_CONFIG_INCLUDED)\n find_package(${PKG_NAME} ${PROJECT_VERSION_FULL_NO_SUFFIX} EXACT \\\${ign_package_quiet} \\\${ign_package_required})\nendif()" DELIM "\n") # Choose what type of pkgconfig entry the core library belongs to set(lib_pkgconfig_type ${component_name}_PKGCONFIG_REQUIRES) if(ign_add_component_PRIVATELY_DEPENDS_ON_PROJECT_LIB AND NOT ign_add_component_INTERFACE_DEPENDS_ON_PROJECT_LIB) set(lib_pkgconfig_type ${lib_pkgconfig_type}_PRIVATE) endif() ign_string_append(${lib_pkgconfig_type} "${PKG_NAME} = ${PROJECT_VERSION_FULL_NO_SUFFIX}") endif() if(ign_add_component_DEPENDS_ON_COMPONENTS) ign_string_append(${component_name}_CMAKE_DEPENDENCIES "find_package(${PKG_NAME} ${PROJECT_VERSION_FULL_NO_SUFFIX} EXACT \\\${ign_package_quiet} \\\${ign_package_required} COMPONENTS ${ign_add_component_DEPENDS_ON_COMPONENTS})" DELIM "\n") endif() #------------------------------------ # Set variables that are needed by cmake/ignition-component-config.cmake.in set(component_pkg_name ${component_target_name}) if(ign_add_component_INTERFACE) set(component_pkgconfig_lib) else() set(component_pkgconfig_lib "-l${component_pkg_name}") endif() set(component_cmake_dependencies ${${component_name}_CMAKE_DEPENDENCIES}) # This next set is redundant, but it serves as a reminder that this input # variable is used in config files set(component_name ${component_name}) # ... and by cmake/pkgconfig/ignition-component.pc.in set(component_pkgconfig_requires ${${component_name}_PKGCONFIG_REQUIRES}) set(component_pkgconfig_requires_private ${${component_name}_PKGCONFIG_REQUIRES_PRIVATE}) set(component_pkgconfig_lib_deps ${${component_name}_PKGCONFIG_LIBS}) set(component_pkgconfig_lib_deps_private ${${component_name}_PKGCONFIG_LIBS_PRIVATE}) set(component_pkgconfig_cflags ${${component_name}_PKGCONFIG_CFLAGS}) # Export and install the cmake target and package information _ign_create_cmake_package(COMPONENT ${component_name}) # Generate and install the pkgconfig information for this component _ign_create_pkgconfig(COMPONENT ${component_name}) #------------------------------------ # Add this component to the "all" target target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME}-all INTERFACE ${lib_name}) get_property(all_known_components TARGET ${PROJECT_LIBRARY_TARGET_NAME}-all PROPERTY INTERFACE_IGN_ALL_KNOWN_COMPONENTS) if(NOT all_known_components) set_property(TARGET ${PROJECT_LIBRARY_TARGET_NAME}-all PROPERTY INTERFACE_IGN_ALL_KNOWN_COMPONENTS "${component_target_name}") else() set_property(TARGET ${PROJECT_LIBRARY_TARGET_NAME}-all PROPERTY INTERFACE_IGN_ALL_KNOWN_COMPONENTS "${all_known_components};${component_target_name}") endif() endfunction() ################################################# function(ign_create_all_target) add_library(${PROJECT_LIBRARY_TARGET_NAME}-all INTERFACE) install( TARGETS ${PROJECT_LIBRARY_TARGET_NAME}-all EXPORT ${PROJECT_LIBRARY_TARGET_NAME}-all LIBRARY DESTINATION ${IGN_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${IGN_LIB_INSTALL_DIR} RUNTIME DESTINATION ${IGN_BIN_INSTALL_DIR} COMPONENT libraries) endfunction() ################################################# function(ign_export_target_all) # find_all_pkg_components is used as a variable in ignition-all-config.cmake.in set(find_all_pkg_components "") get_property(all_known_components TARGET ${PROJECT_LIBRARY_TARGET_NAME}-all PROPERTY INTERFACE_IGN_ALL_KNOWN_COMPONENTS) if(all_known_components) foreach(component ${all_known_components}) ign_string_append(find_all_pkg_components "find_dependency(${component} ${PROJECT_VERSION_FULL_NO_SUFFIX} EXACT)" DELIM "\n") endforeach() endif() _ign_create_cmake_package(ALL) endfunction() ################################################# # Used internally by _ign_add_library_or_component to report argument errors macro(_ign_add_library_or_component_arg_error missing_arg) message(FATAL_ERROR "ignition-cmake developer error: Must specify " "${missing_arg} to _ign_add_library_or_component!") endmacro() ################################################# # This is only meant for internal use by ignition-cmake. If you are a consumer # of ignition-cmake, please use ign_create_core_library(~) or # ign_add_component(~) instead of this. # # _ign_add_library_or_component(LIB_NAME # INCLUDE_DIR # EXPORT_BASE # SOURCES ) # macro(_ign_add_library_or_component) # NOTE: The following local variables are used in the Export.hh.in file, so if # you change their names here, you must also change their names there: # - include_dir # - export_base # - lib_name #------------------------------------ # Define the expected arguments set(options INTERFACE) set(oneValueArgs LIB_NAME INCLUDE_DIR EXPORT_BASE) set(multiValueArgs SOURCES) #------------------------------------ # Parse the arguments cmake_parse_arguments(_ign_add_library "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(_ign_add_library_LIB_NAME) set(lib_name ${_ign_add_library_LIB_NAME}) else() _ign_add_library_or_component_arg_error(LIB_NAME) endif() if(NOT _ign_add_library_INTERFACE) if(_ign_add_library_SOURCES) set(sources ${_ign_add_library_SOURCES}) else() _ign_add_library_or_component_arg_error(SOURCES) endif() else() set(sources) endif() if(_ign_add_library_INCLUDE_DIR) set(include_dir ${_ign_add_library_INCLUDE_DIR}) else() _ign_add_library_or_component_arg_error(INCLUDE_DIR) endif() if(_ign_add_library_EXPORT_BASE) set(export_base ${_ign_add_library_EXPORT_BASE}) else() _ign_add_library_or_component_arg_error(EXPORT_BASE) endif() # check that export_base has no invalid symbols string(REPLACE "-" "_" export_base_replaced ${export_base}) if(NOT ${export_base} STREQUAL ${export_base_replaced}) message(FATAL_ERROR "export_base has a hyphen which is not" "supported by macros used for visibility") endif() #------------------------------------ # Create the library target message(STATUS "Configuring library: ${lib_name}") if(_ign_add_library_INTERFACE) add_library(${lib_name} INTERFACE) else() add_library(${lib_name} ${sources}) endif() #------------------------------------ # Add fPIC if we are supposed to if(IGN_ADD_fPIC_TO_LIBRARIES AND NOT _ign_add_library_INTERFACE) target_compile_options(${lib_name} PRIVATE -fPIC) endif() if(NOT _ign_add_library_INTERFACE) #------------------------------------ # Generate export macro headers # Note: INTERFACE libraries do not need the export header set(binary_include_dir "${CMAKE_BINARY_DIR}/include/${include_dir}") set(implementation_file_name "${binary_include_dir}/detail/Export.hh") include(GenerateExportHeader) # This macro will generate a header called detail/Export.hh which implements # some C-macros that are useful for exporting our libraries. The # implementation header does not provide any commentary or explanation for its # macros, so we tuck it away in the detail/ subdirectory, and then provide a # public-facing header that provides commentary for the macros. generate_export_header(${lib_name} BASE_NAME ${export_base} EXPORT_FILE_NAME ${implementation_file_name} EXPORT_MACRO_NAME DETAIL_${export_base}_VISIBLE NO_EXPORT_MACRO_NAME DETAIL_${export_base}_HIDDEN DEPRECATED_MACRO_NAME IGN_DEPRECATED_ALL_VERSIONS) set(install_include_dir "${IGN_INCLUDE_INSTALL_DIR_FULL}/${include_dir}") # Configure the installation of the automatically generated file. install( FILES "${implementation_file_name}" DESTINATION "${install_include_dir}/detail" COMPONENT headers) # Configure the public-facing header for exporting and deprecating. This # header provides commentary for the macros so that developers can know their # purpose. configure_file( "${IGNITION_CMAKE_DIR}/Export.hh.in" "${binary_include_dir}/Export.hh") # Configure the installation of the public-facing header. install( FILES "${binary_include_dir}/Export.hh" DESTINATION "${install_include_dir}" COMPONENT headers) set_target_properties( ${lib_name} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR} VERSION ${PROJECT_VERSION_FULL}) endif() #------------------------------------ # Configure the installation of the target install( TARGETS ${lib_name} EXPORT ${lib_name} LIBRARY DESTINATION ${IGN_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${IGN_LIB_INSTALL_DIR} RUNTIME DESTINATION ${IGN_BIN_INSTALL_DIR} COMPONENT libraries) endmacro() ################################################# macro(ign_add_executable _name) add_executable(${_name} ${ARGN}) target_link_libraries(${_name} ${general_libraries}) endmacro() ################################################# # ign_target_interface_include_directories( [include_targets]) # # Add the INTERFACE_INCLUDE_DIRECTORIES of [include_targets] to the public # INCLUDE_DIRECTORIES of . This allows us to propagate the include # directories of along to any other libraries that depend on it. # # You MUST pass in targets to include, not directory names. We must not use # explicit directory names here if we want our package to be relocatable. function(ign_target_interface_include_directories name) foreach(include_target ${ARGN}) target_include_directories( ${name} PUBLIC $) endforeach() endfunction() ################################################# macro(ign_install_includes _subdir) install(FILES ${ARGN} DESTINATION ${IGN_INCLUDE_INSTALL_DIR}/${_subdir} COMPONENT headers) endmacro() ################################################# macro(ign_install_library) message(FATAL_ERROR "ign_install_library is deprecated. " "Please remove it from your cmake script!") endmacro() ################################################# macro(ign_install_executable _name ) set_target_properties(${_name} PROPERTIES VERSION ${PROJECT_VERSION_FULL}) install (TARGETS ${_name} DESTINATION ${IGN_BIN_INSTALL_DIR}) manpage(${_name} 1) endmacro() ################################################# # Macro to setup supported compiler warnings # Based on work of Florent Lamiraux, Thomas Moulard, JRL, CNRS/AIST. macro(ign_filter_valid_compiler_options var) include(CheckCXXCompilerFlag) # Store the current setting for CMAKE_REQUIRED_QUIET set(original_cmake_required_quiet ${CMAKE_REQUIRED_QUIET}) # Make these tests quiet so they don't pollute the cmake output set(CMAKE_REQUIRED_QUIET true) foreach(flag ${ARGN}) CHECK_CXX_COMPILER_FLAG(${flag} result${flag}) if(result${flag}) set(${var} "${${var}} ${flag}") endif() endforeach() # Restore the old setting for CMAKE_REQUIRED_QUIET set(CMAKE_REQUIRED_QUIET ${original_cmake_required_quiet}) endmacro() ################################################# # ign_build_executables(SOURCES # [PREFIX ] # [LIB_DEPS ] # [INCLUDE_DIRS ] # [EXEC_LIST ] # [EXCLUDE_PROJECT_LIB]) # # Build executables for an ignition project. Arguments are as follows: # # SOURCES: Required. The names (without a path) of the source files for your # executables. # # PREFIX: Optional. This will append onto each executable name. # # LIB_DEPS: Optional. Additional library dependencies that every executable # should link to, not including the library build by this project (it # will be linked automatically, unless you pass in the # EXCLUDE_PROJECT_LIB option). # # INCLUDE_DIRS: Optional. Additional include directories that should be visible # to all of these executables. # # EXEC_LIST: Optional. Provide a variable which will be given the list of the # names of the executables generated by this macro. These will also # be the names of the targets. # # EXCLUDE_PROJECT_LIB: Pass this argument if you do not want your executables to # link to your project's core library. On Windows, this # will also skip the step of copying the runtime library # into your executable's directory. # macro(ign_build_executables) #------------------------------------ # Define the expected arguments set(options EXCLUDE_PROJECT_LIB) set(oneValueArgs PREFIX EXEC_LIST) set(multiValueArgs SOURCES LIB_DEPS INCLUDE_DIRS) if(ign_build_executables_EXEC_LIST) set(${ign_build_executables_EXEC_LIST} "") endif() #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_build_executables "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) foreach(exec_file ${ign_build_executables_SOURCES}) get_filename_component(BINARY_NAME ${exec_file} NAME_WE) set(BINARY_NAME ${ign_build_executables_PREFIX}${BINARY_NAME}) add_executable(${BINARY_NAME} ${exec_file}) if(ign_build_executables_EXEC_LIST) list(APPEND ${ign_build_executables_EXEC_LIST} ${BINARY_NAME}) endif() if(NOT ign_build_executables_EXCLUDE_PROJECT_LIB) target_link_libraries(${BINARY_NAME} ${PROJECT_LIBRARY_TARGET_NAME}) endif() if(ign_build_executables_LIB_DEPS) target_link_libraries(${BINARY_NAME} ${ign_build_executables_LIB_DEPS}) endif() target_include_directories(${BINARY_NAME} PRIVATE ${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR} ${ign_build_executables_INCLUDE_DIRS}) endforeach() endmacro() ################################################# # ign_build_tests(TYPE # SOURCES # [LIB_DEPS ] # [INCLUDE_DIRS ] # [TEST_LIST ]) # # Build tests for an ignition project. Arguments are as follows: # # TYPE: Required. Preferably UNIT, INTEGRATION, PERFORMANCE, or REGRESSION. # # SOURCES: Required. The names (without the path) of the source files for your # tests. Each file will turn into a test. # # LIB_DEPS: Optional. Additional library dependencies that every test should # link to, not including the library built by this project (it will be # linked automatically). gtest and gtest_main will also be linked. # # INCLUDE_DIRS: Optional. Additional include directories that should be visible # to all the tests of this type. # # TEST_LIST: Optional. Provide a variable which will be given the list of the # names of the tests generated by this macro. These will also be the # names of the targets. # # EXCLUDE_PROJECT_LIB: Pass this argument if you do not want your tests to # link to your project's core library. On Windows, this # will also skip the step of copying the runtime library # into your executable's directory. # macro(ign_build_tests) #------------------------------------ # Define the expected arguments set(options SOURCE EXCLUDE_PROJECT_LIB) # NOTE: DO NOT USE "SOURCE", we're adding it here to catch typos set(oneValueArgs TYPE TEST_LIST) set(multiValueArgs SOURCES LIB_DEPS INCLUDE_DIRS) #------------------------------------ # Parse the arguments _ign_cmake_parse_arguments(ign_build_tests "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(NOT ign_build_tests_TYPE) # If you have encountered this error, you are probably migrating to the # new ignition-cmake system. Be sure to also provide a SOURCES argument # when calling ign_build_tests. message(FATAL_ERROR "Developer error: You must specify a TYPE for your tests!") endif() if(ign_build_tests_SOURCE) # We have encountered cases where someone accidentally passes a SOURCE # argument instead of a SOURCES argument into ign_build_tests, and the macro # didn't report any problem with it. Adding this warning should make it more # clear when that particular typo occurs. message(AUTHOR_WARNING "Your script has specified SOURCE for ign_build_tests, which is not an " "option. Did you mean to specify SOURCES (note the plural)?") endif() set(TEST_TYPE ${ign_build_tests_TYPE}) if(BUILD_TESTING) if(NOT DEFINED ign_build_tests_SOURCES) message(STATUS "No tests have been specified for ${TEST_TYPE}") else() list(LENGTH ign_build_tests_SOURCES num_tests) message(STATUS "Adding ${num_tests} ${TEST_TYPE} tests") endif() if(NOT ign_build_tests_EXCLUDE_PROJECT_LIB) ign_build_executables( PREFIX "${TEST_TYPE}_" SOURCES ${ign_build_tests_SOURCES} LIB_DEPS gtest gtest_main ${ign_build_tests_LIB_DEPS} INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/test/gtest/include ${ign_build_tests_INCLUDE_DIRS} EXEC_LIST test_list) else() ign_build_executables( PREFIX "${TEST_TYPE}_" SOURCES ${ign_build_tests_SOURCES} LIB_DEPS gtest gtest_main ${ign_build_tests_LIB_DEPS} INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/test/gtest/include ${ign_build_tests_INCLUDE_DIRS} EXEC_LIST test_list EXCLUDE_PROJECT_LIB) endif() if(ign_build_tests_TEST_LIST) set(${ign_build_tests_TEST_LIST} ${test_list}) endif() # Find the Python interpreter for running the # check_test_ran.py script include(IgnPython) # Build all the tests foreach(target_name ${test_list}) if(USE_LOW_MEMORY_TESTS) target_compile_options(${target_name} PRIVATE -DUSE_LOW_MEMORY_TESTS=1) endif() add_test(NAME ${target_name} COMMAND ${target_name} --gtest_output=xml:${CMAKE_BINARY_DIR}/test_results/${target_name}.xml) if(UNIX) # gtest requies pthread when compiled on a Unix machine target_link_libraries(${target_name} pthread) endif() set_tests_properties(${target_name} PROPERTIES TIMEOUT 240) if(PYTHONINTERP_FOUND) # Check that the test produced a result and create a failure if it didn't. # Guards against crashed and timed out tests. add_test(check_${target_name} ${PYTHON_EXECUTABLE} ${IGNITION_CMAKE_TOOLS_DIR}/check_test_ran.py ${CMAKE_BINARY_DIR}/test_results/${target_name}.xml) endif() endforeach() else() message(STATUS "Testing is disabled -- skipping ${TEST_TYPE} tests") endif() endmacro() ################################################# # ign_set_target_public_cxx_standard(<11|14|17>) # # NOTE: This was a temporary workaround for an earlier prerelease and is # deprecated as of the "Components" pull request. # macro(ign_set_project_public_cxx_standard standard) message(FATAL_ERROR "The ign_set_project_public_cxx_standard(~) macro is deprecated. " "Instead, use the CXX_STANDARD argument of ign_create_core_library(~).") _ign_check_known_cxx_standards(${standard}) target_compile_features(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ${IGN_CXX_${standard}_FEATURES}) # Note: We have to reconfigure the pkg-config information for the core library # because this macro can only be called after ign_create_core_library(~). This # is somewhat wasteful, so we should strongly prefer to use the CXX_STANDARD # argument of ign_create_core_library(~). ign_string_append(PROJECT_PKGCONFIG_CFLAGS "-std=c++${standard}") _ign_create_pkgconfig() endmacro() ################################################# # _ign_cmake_parse_arguments( [ARGN]) # # Set to match the prefix that is given to cmake_parse_arguments(~). # This should also match the name of the function or macro that called it. # # NOTE: This should only be used by functions inside of ign-cmake specifically. # Other ignition projects should not use this macro. # macro(_ign_cmake_parse_arguments prefix options oneValueArgs multiValueArgs) cmake_parse_arguments(${prefix} "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(${prefix}_UNPARSED_ARGUMENTS) # The user passed in some arguments that we don't currently recognize. We'll # emit a warning so they can check whether they're using the correct version # of ign-cmake. message(AUTHOR_WARNING "\nThe build script has specified some unrecognized arguments for ${prefix}(~):\n" "${${prefix}_UNPARSED_ARGUMENTS}\n" "Either the script has a typo, or it is using an unexpected version of ign-cmake. " "The version of ign-cmake currently being used is ${ignition-cmake${IGNITION_CMAKE_VERSION_MAJOR}_VERSION}\n") endif() endmacro() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnGenerateVersionInfo.cmake0000664000175000017500000000545714160533245025063 0ustar jriverojrivero#.rst # IgnGenerateVersionInfo # ---------------------- # # Intended to be invoked as part of the ign_add_version_info_target function # in IgnBenchmark. # # Populates information in the version_info.json file. # #=============================================================================== # Copyright (C) 2019 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Retrieve information about the mercurial state. execute_process( COMMAND hg id --id WORKING_DIRECTORY ${repository_root} OUTPUT_VARIABLE HG_GLOBAL_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND hg id --num WORKING_DIRECTORY ${repository_root} OUTPUT_VARIABLE HG_REVISION_NUM OUTPUT_STRIP_TRAILING_WHITESPACE ) execute_process( COMMAND hg id --branch WORKING_DIRECTORY ${repository_root} OUTPUT_VARIABLE HG_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE ) # Set time that this build occurred. # Adding a dependency to this target will cause this file to be generated # with each build, updating the timestamp accordingly. string(TIMESTAMP build_time UTC) # Retrieve information about the host system # Ref: https://cmake.org/cmake/help/latest/command/cmake_host_system_information.html cmake_host_system_information(RESULT NUM_LOGICAL QUERY NUMBER_OF_LOGICAL_CORES) cmake_host_system_information(RESULT NUM_PHYSICAL QUERY NUMBER_OF_PHYSICAL_CORES) cmake_host_system_information(RESULT HOST QUERY HOSTNAME) cmake_host_system_information(RESULT FQDN QUERY FQDN) cmake_host_system_information(RESULT TOTAL_VIRTUAL QUERY TOTAL_VIRTUAL_MEMORY) cmake_host_system_information(RESULT AVAILABLE_VIRTUAL QUERY AVAILABLE_VIRTUAL_MEMORY) cmake_host_system_information(RESULT TOTAL_PHYSICAL QUERY TOTAL_PHYSICAL_MEMORY) cmake_host_system_information(RESULT AVAILABLE_PHYSICAL QUERY AVAILABLE_PHYSICAL_MEMORY) cmake_host_system_information(RESULT PROC_NAME QUERY PROCESSOR_NAME) cmake_host_system_information(RESULT PROC_DESC QUERY PROCESSOR_DESCRIPTION) cmake_host_system_information(RESULT PROC_SERIAL QUERY PROCESSOR_SERIAL_NUMBER) cmake_host_system_information(RESULT OS_NAME QUERY OS_NAME) cmake_host_system_information(RESULT OS_RELEASE QUERY OS_RELEASE) cmake_host_system_information(RESULT OS_VERSION QUERY OS_VERSION) cmake_host_system_information(RESULT OS_PLATFORM QUERY OS_PLATFORM) configure_file(${input_file} ${output_file}) ign-cmake-ignition-cmake2_2.10.0/cmake/Export.hh.in0000664000175000017500000000453614160533245021713 0ustar jriverojrivero/* * Copyright (C) 2017 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ /* * ========================================================================== * This file was automatically generated by CMake; do not modify it directly. * To modify this file, make changes to ign-cmake/cmake/Export.hh.in * ========================================================================== */ #ifndef @export_base@_EXPORT_HH_ #define @export_base@_EXPORT_HH_ // The detail/Export.hh header is automatically generated by CMake, which only // provides the system-dependent implementations of these macros, with no // commentary or explanation, so we configure this public-facing header which // leverages the auto-generated macros but provides commentary for them. #include "@include_dir@/detail/Export.hh" #ifndef @export_base@_VISIBLE /// For @lib_name@ developers: Apply this macro to @lib_name@ /// functions and classes which consumers of this library will need to be able /// to call from their own programs or libraries. #define @export_base@_VISIBLE \ DETAIL_@export_base@_VISIBLE #endif #ifndef @export_base@_HIDDEN /// For @lib_name@ developers: Apply this macro to @lib_name@ /// functions and classes which must not be used by consumers of this library. /// By default, this property is applied to all classes and functions which are /// not tagged with @export_base@_VISIBLE, so this does not /// generally need to be used. #define @export_base@_HIDDEN \ DETAIL_@export_base@_HIDDEN #endif #ifndef IGN_DEPRECATED /// For @lib_name@ developers: Use this macro to indicate that a /// function or class has been deprecated and should no longer be used. A /// version should be specified to provide context to the user about when the /// function became deprecated. #define IGN_DEPRECATED(version) IGN_DEPRECATED_ALL_VERSIONS #endif #endif ign-cmake-ignition-cmake2_2.10.0/cmake/FindJSONCPP.cmake0000664000175000017500000000475714160533245022430 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find jsoncpp. # # Usage of this module as follows: # # find_package(JSONCPP) # # Variables defined by this module: # # JSONCPP_FOUND System has JSONCPP libs/headers # JSONCPP_INCLUDE_DIRS The location of JSONCPP headers # JSONCPP_LIBRARIES The JSONCPP libraries # JSONCPP_TARGET Imported target for libjsoncpp if(JSONCPP_FIND_VERSION) message(WARNING "FindJSONCPP doesn't support the request of specific " "versions. Please do not use VERSION.") else() find_package(jsoncpp CONFIG QUIET) set(JSONCPP_TARGET jsoncpp_lib) include(IgnPkgConfig) if(JSONCPP_FOUND) ign_pkg_config_entry(JSONCPP jsoncpp) else() ign_pkg_check_modules_quiet(JSONCPP jsoncpp) set(JSONCPP_TARGET JSONCPP::JSONCPP) # If that failed, then fall back to manual detection. if(NOT JSONCPP_FOUND) if(NOT JSONCPP_FIND_QUIETLY) message(STATUS "Attempting manual search for jsoncpp") endif() find_path(JSONCPP_INCLUDE_DIRS json/json.h ${JSONCPP_INCLUDE_DIRS} ENV CPATH) find_library(JSONCPP_LIBRARIES NAMES jsoncpp) set(JSONCPP_FOUND true) if(NOT JSONCPP_INCLUDE_DIRS) if(NOT JSONCPP_FIND_QUIETLY) message(STATUS "Looking for jsoncpp headers - not found") endif() set(JSONCPP_FOUND false) endif() if(NOT JSONCPP_LIBRARIES) if(NOT JSONCPP_FIND_QUIETLY) message (STATUS "Looking for jsoncpp library - not found") endif() set(JSONCPP_FOUND false) endif() if(JSONCPP_FOUND) include(IgnImportTarget) ign_import_target(JSONCPP) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( JSONCPP REQUIRED_VARS JSONCPP_FOUND) endif() endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindDL.cmake0000664000175000017500000000540514160533245021602 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find libdl if(MSVC) # The dlfcn-win32 library installs a config module, so we should leverage that find_package(dlfcn-win32) # Note: Ideally, we would create an alias target for dlfcn-win32::dl, but # cmake does not (currently) support aliasing imported targets # (see: https://gitlab.kitware.com/cmake/cmake/issues/15569) # # For now, we will use a variable named DL_TARGET for linking, even though # it is old-fashioned. If a day comes when cmake supported aliasing # imported targets, then we should migrate to something like # # add_library(DL::DL ALIAS dlfcn-win32::dl) # # And then link to DL::DL. set(DL_TARGET dlfcn-win32::dl) if(dlfcn-win32_FOUND) set(DL_FOUND true) else() set(DL_FOUND false) endif() else() # NOTE: libdl is a system library on UNIX, so it does not come with pkgconfig metadata # If we cannot find the header or the library, we will switch this to false set(DL_FOUND true) # Search for the header find_path(DL_INCLUDE_DIRS dlfcn.h) if(DL_INCLUDE_DIRS) if(NOT DL_FIND_QUIETLY) message(STATUS "Looking for dlfcn.h - found") endif() else(DL_INCLUDE_DIRS) if(NOT DL_FIND_QUIETLY) message(STATUS "Looking for dlfcn.h - not found") endif() set(DL_FOUND false) endif() mark_as_advanced(DL_INCLUDE_DIRS) # Search for the library find_library(DL_LIBRARIES dl) if(DL_LIBRARIES) if(NOT DL_FIND_QUIETLY) message(STATUS "Looking for libdl - found") endif() else(DL_LIBRARIES) if(NOT DL_FIND_QUIETLY) message(STATUS "Looking for libdl - not found") endif() set(DL_FOUND false) endif() mark_as_advanced(DL_LIBRARIES) if(DL_FOUND) include(IgnImportTarget) ign_import_target(DL) set(DL_TARGET DL::DL) endif() endif() # We need to manually specify the pkgconfig entry (and type of entry) for dl, # because ign_pkg_check_modules does not work for it. include(IgnPkgConfig) ign_pkg_config_library_entry(DL dl) include(FindPackageHandleStandardArgs) find_package_handle_standard_args( DL REQUIRED_VARS DL_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/FindYAML.cmake0000664000175000017500000000555714160533245022055 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find yaml. # # Usage of this module as follows: # # find_package(YAML) # # Variables defined by this module: # # YAML_TARGET Imported target for libyaml # # YAML_FOUND System has YAML libs/headers # YAML_INCLUDE_DIRS The location of YAML headers # YAML_LIBRARIES The YAML libraries # initialize this variable to the default target name set(YAML_TARGET YAML::YAML) find_package(yaml ${YAML_FIND_VERSION} CONFIG QUIET) if (yaml_FOUND) # yaml's cmake script imports its own target, so we'll # overwrite the default with the name of theirs. In the # future, we should be able to use a target alias instead. set(YAML_TARGET yaml) set(YAML_FOUND True) set(YAML_INCLUDE_DIRS ${yaml_INCLUDE_DIRS}) set(YAML_LIBRARIES ${yaml_LIBRARIES}) return() endif() if(YAML_FIND_VERSION AND NOT YAML_FIND_VERSION VERSION_EQUAL "0.1") message(WARNING "FindYAML only knows how to find version 0.1 " "but you requested version ${YAML_FIND_VERSION}.") else() include(IgnPkgConfig) ign_pkg_check_modules_quiet(YAML yaml-0.1) # If that failed, then fall back to manual detection. if(NOT YAML_FOUND) if(NOT YAML_FIND_QUIETLY) message(STATUS "Attempting manual search for yaml") endif() find_path(YAML_INCLUDE_DIRS yaml.h ${YAML_INCLUDE_DIRS} ENV CPATH) find_library(YAML_LIBRARIES NAMES yaml) set(YAML_FOUND true) if(NOT YAML_INCLUDE_DIRS) if(NOT YAML_FIND_QUIETLY) message(STATUS "Looking for yaml headers - not found") endif() set(YAML_FOUND false) endif() if(NOT YAML_LIBRARIES) if(NOT YAML_FIND_QUIETLY) message (STATUS "Looking for yaml library - not found") endif() set(YAML_FOUND false) endif() if(YAML_FOUND) include(IgnImportTarget) ign_import_target(YAML) message(STATUS "Assuming libyaml is static, defining YAML_DECLARE_STATIC") set_target_properties(YAML::YAML PROPERTIES INTERFACE_COMPILE_DEFINITIONS "YAML_DECLARE_STATIC" ) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( YAML REQUIRED_VARS YAML_FOUND) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnOGRE.cmake0000664000175000017500000002470614160533245022502 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2018 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## #-------------------------------------- # Find OGRE headers and libraries # # Usage of this module as follows: # # ign_find_package(IgnOGRE) # # Variables defined by this module: # # OGRE_FOUND System has OGRE libs/headers # OGRE_LIBRARIES The OGRE libraries # OGRE_INCLUDE_DIRS The location of OGRE headers # OGRE_VERSION Full OGRE version in the form of MAJOR.MINOR.PATCH # OGRE_VERSION_MAJOR OGRE major version # OGRE_VERSION_MINOR OGRE minor version # OGRE_VERSION_PATCH OGRE patch version # OGRE_RESOURCE_PATH Path to ogre plugins directory # IgnOGRE::IgnOGRE Imported target for OGRE # # On Windows, we assume that all the OGRE* defines are passed in manually # to CMake. # # Supports finding the following OGRE components: RTShaderSystem, Terrain, Overlay # # Example usage: # # ign_find_package(IgnOGRE # VERSION 1.8.0 # COMPONENTS RTShaderSystem Terrain Overlay) # Grab the version numbers requested by the call to find_package(~) set(major_version ${IgnOGRE_FIND_VERSION_MAJOR}) set(minor_version ${IgnOGRE_FIND_VERSION_MINOR}) # Set the full version number set(full_version ${major_version}.${minor_version}) # Copied from OGREConfig.cmake macro(ign_ogre_declare_plugin TYPE COMPONENT) set(OGRE_${TYPE}_${COMPONENT}_FOUND TRUE) set(OGRE_${TYPE}_${COMPONENT}_LIBRARIES ${TYPE}_${COMPONENT}) list(APPEND OGRE_LIBRARIES ${TYPE}_${COMPONENT}) endmacro() if (NOT WIN32) # pkg-config platforms set(PKG_CONFIG_PATH_ORIGINAL $ENV{PKG_CONFIG_PATH}) set(PKG_CONFIG_PATH_TMP ${PKG_CONFIG_PATH_ORIGINAL}) execute_process(COMMAND pkg-config --variable pc_path pkg-config OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed) if(_pkgconfig_failed) IGN_BUILD_WARNING ("Failed to get pkg-config search paths") elseif (NOT _pkgconfig_invoke_result STREQUAL "") set (PKG_CONFIG_PATH_TMP "${PKG_CONFIG_PATH_TMP}:${_pkgconfig_invoke_result}") endif() # check and see if there are any paths at all if ("${PKG_CONFIG_PATH_TMP}" STREQUAL "") message("No valid pkg-config search paths found") return() endif() string(REPLACE ":" ";" PKG_CONFIG_PATH_TMP ${PKG_CONFIG_PATH_TMP}) # loop through pkg config paths and find an ogre version that is < 2.0.0 foreach(pkg_path ${PKG_CONFIG_PATH_TMP}) if (NOT EXISTS ${pkg_path}) continue() endif() set(OGRE_FOUND false) set(OGRE_INCLUDE_DIRS "") set(OGRE_LIBRARY_DIRS "") set(OGRE_LIBRARIES "") set(ENV{PKG_CONFIG_PATH} ${pkg_path}) ign_pkg_check_modules_quiet(OGRE "OGRE >= ${full_version}" NO_CMAKE_ENVIRONMENT_PATH QUIET) if (OGRE_FOUND) if (NOT ${OGRE_VERSION} VERSION_LESS 2.0.0) set (OGRE_FOUND false) else () # set library dirs if the value is empty if (NOT ${OGRE_LIBRARY_DIRS} OR ${OGRE_LIBRARY_DIRS} STREQUAL "") execute_process(COMMAND pkg-config --variable=libdir OGRE OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed) if(_pkgconfig_failed) IGN_BUILD_WARNING ("Failed to find OGRE's library directory. The build will succeed, but there will likely be run-time errors.") else() # set ogre library dir and strip line break set(OGRE_LIBRARY_DIRS ${_pkgconfig_invoke_result}) string(REGEX REPLACE "\n$" "" OGRE_LIBRARY_DIRS "${OGRE_LIBRARY_DIRS}") string(FIND "${OGRE_LIBRARIES}" "${OGRE_LIBRARY_DIRS}" substr_found) # in some cases the value of OGRE_LIBRARIES is "OgreMain;pthread" # Convert this to full path to library if (substr_found EQUAL -1) foreach(OGRE_LIBRARY_NAME ${OGRE_LIBRARIES}) find_library(OGRE_LIBRARY NAMES ${OGRE_LIBRARY_NAME} HINTS ${OGRE_LIBRARY_DIRS} NO_DEFAULT_PATH) list (APPEND TMP_OGRE_LIBRARIES "${OGRE_LIBRARY}") endforeach() set(OGRE_LIBRARIES ${TMP_OGRE_LIBRARIES}) endif() endif() endif() break() endif() endif() endforeach() if (OGRE_FOUND) # set OGRE major, minor, and patch version number string (REGEX REPLACE "^([0-9]+).*" "\\1" OGRE_VERSION_MAJOR "${OGRE_VERSION}") string (REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" OGRE_VERSION_MINOR "${OGRE_VERSION}") string (REGEX REPLACE "^[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" OGRE_VERSION_PATCH ${OGRE_VERSION}) # find ogre components foreach(component ${IgnOGRE_FIND_COMPONENTS}) ign_pkg_check_modules_quiet(IgnOGRE-${component} "OGRE-${component} >= ${full_version}" NO_CMAKE_ENVIRONMENT_PATH) if(IgnOGRE-${component}_FOUND) list(APPEND OGRE_LIBRARIES IgnOGRE-${component}::IgnOGRE-${component}) elseif(IgnOGRE_FIND_REQUIRED_${component}) set(OGRE_FOUND false) endif() endforeach() execute_process(COMMAND pkg-config --variable=plugindir OGRE OUTPUT_VARIABLE _pkgconfig_invoke_result RESULT_VARIABLE _pkgconfig_failed) if(_pkgconfig_failed) IGN_BUILD_WARNING ("Failed to find OGRE's plugin directory. The build will succeed, but there will likely be run-time errors.") else() # This variable will be substituted into cmake/setup.sh.in set(OGRE_PLUGINDIR ${_pkgconfig_invoke_result}) endif() ign_pkg_config_library_entry(IgnOGRE OgreMain) set(OGRE_RESOURCE_PATH ${OGRE_PLUGINDIR}) # Seems that OGRE_PLUGINDIR can end in a newline, which will cause problems # when we pass it to the compiler later. string(REPLACE "\n" "" OGRE_RESOURCE_PATH ${OGRE_RESOURCE_PATH}) endif() #reset pkg config path set(ENV{PKG_CONFIG_PATH} ${PKG_CONFIG_PATH_ORIGINAL}) else() find_package(OGRE ${full_version} COMPONENTS ${IgnOGRE_FIND_COMPONENTS}) if(OGRE_FOUND) # OGREConfig.cmake from vcpkg disable the link against plugin libs # when compiling the shared version of it. Here we copied the code # to use it. foreach(ogre_component ${IgnOGRE_FIND_COMPONENTS}) if(ogre_component MATCHES "Plugin_" OR ogre_component MATCHES "RenderSystem_") string(LENGTH "${ogre_component}" len) string(FIND "${ogre_component}" "_" split_pos) math(EXPR split_pos2 "${split_pos}+1") string(SUBSTRING "${ogre_component}" "0" "${split_pos}" component_type) string(SUBSTRING "${ogre_component}" "${split_pos2}" "${len}" component_name) ign_ogre_declare_plugin("${component_type}" "${component_name}") endif() endforeach() # need to return only libraries defined by components and give them the # full path using OGRE_LIBRARY_DIRS # Note: the OGREConfig.cmake installed by vcpkg generates variables that # contain unwanted substrings so the string regex replace is added to # fix the ogre dir path and lib vars. # TODO(anyone) check if this is an OGRE vcpkg config issue. string(REGEX REPLACE "\\$.*>" "" OGRE_LIBRARY_DIRS ${OGRE_LIBRARY_DIRS}) set(ogre_all_libs) foreach(ogre_lib ${OGRE_LIBRARIES}) # dirty hack to be able to know which ogre libraries are defined by the # absolute paths. These variables are sometimes multi-configuration vars # (i.e: C:/vcpkg/installed/x64-windows$<$:/debug>/..) # IS_ABSOLUTE cmake function seems not to be working fine with them. string(SUBSTRING "${OGRE_LIBRARY_DIRS}" 0 5 PATH_PREFIX) string(SUBSTRING "${ogre_lib}" 0 5 ogrelib_PATH_PREFIX) if(ogrelib_PATH_PREFIX STREQUAL PATH_PREFIX) set(lib_fullpath "${ogre_lib}") else() string(REGEX REPLACE "\\$.*>" "" ogre_lib ${ogre_lib}) # Be sure that all Ogre* libraries are using absolute paths set(prefix "") # vcpkg uses special directory (lib/manual-link/) to place libraries # with main sysmbol like OgreMain. if(ogre_lib MATCHES "OgreMain" AND NOT IS_ABSOLUTE "${ogre_lib}" AND EXISTS "${OGRE_LIBRARY_DIRS}/manual-link/") set(prefix "${OGRE_LIBRARY_DIRS}/manual-link/") elseif(ogre_lib MATCHES "Ogre" AND NOT IS_ABSOLUTE "${ogre_lib}") set(prefix "${OGRE_LIBRARY_DIRS}/") endif() if(ogre_lib MATCHES "Plugin_" OR ogre_lib MATCHES "RenderSystem_") if(NOT IS_ABSOLUTE "${ogre_lib}") set(prefix "${OGRE_LIBRARY_DIRS}/OGRE/") endif() endif() # Some Ogre libraries are not using the .lib extension set(postfix "") if(NOT ogre_lib MATCHES ".lib$") # Do not consider imported targets as libraries if(NOT ogre_lib MATCHES "::") set(postfix ".lib") endif() endif() set(lib_fullpath "${prefix}${ogre_lib}${postfix}") endif() list(APPEND ogre_all_libs ${lib_fullpath}) endforeach() set(OGRE_LIBRARIES ${ogre_all_libs}) set(OGRE_RESOURCE_PATH ${OGRE_CONFIG_DIR}) endif() endif() set(IgnOGRE_FOUND false) if(OGRE_FOUND) set(IgnOGRE_FOUND true) # manually search and append the the RenderSystem/GL path to # OGRE_INCLUDE_DIRS so OGRE GL headers can be found foreach(dir ${OGRE_INCLUDE_DIRS}) get_filename_component(dir_name "${dir}" NAME) if("${dir_name}" STREQUAL "OGRE") if(${OGRE_VERSION} VERSION_LESS 1.11.0) set(dir_include "${dir}/RenderSystems/GL") else() set(dir_include "${dir}/RenderSystems/GL" "${dir}/Paging") endif() else() set(dir_include "${dir}") endif() list(APPEND OGRE_INCLUDE_DIRS ${dir_include}) endforeach() include(IgnImportTarget) ign_import_target(IgnOGRE TARGET_NAME IgnOGRE::IgnOGRE LIB_VAR OGRE_LIBRARIES INCLUDE_VAR OGRE_INCLUDE_DIRS) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/IgnBenchmark.cmake0000664000175000017500000000671714160533245023041 0ustar jriverojrivero#.rst # IgnBenchmark # ------------ # # ign_add_version_info_target() # # Adds a target to generate build and system configuration information. # # ign_add_benchmarks() # # Adds a target to execute all available benchmarks and aggregate the results. # # USAGE: # 1. Add the following line to your CMakeLists.txt # include(IgnBenchmark) # # 2. Add the benchmark # ign_add_benchmarks(SOURCES ${benchmark_sources_list}) # # 3. After building the project, use `make run_benchmarks` to execute and # aggregate benchmark results to ${CMAKE_BINARY_DIR}/benchmark_results # #=============================================================================== # Copyright (C) 2019 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. function(ign_add_version_info_target) # generate a version_info.json file that can be used to embed project # version information # While this command may look a bit unweildy, it creates a target # that forces the file to be regenerated at build time. add_custom_target(version_info_target COMMAND ${CMAKE_COMMAND} -Dinput_file=${IGNITION_CMAKE_DIR}/version_info.json.in -Doutput_file=${CMAKE_CURRENT_BINARY_DIR}/version_info.json -Drepository_root=${CMAKE_CURRENT_SOURCE_DIR} # Yes, these variables need to be passed in, because they won't # get properly set when invoked as a CMake script. -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DPROJECT_VERSION=${PROJECT_VERSION} -DPROJECT_VERSION_FULL=${PROJECT_VERSION_FULL} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} -DPROJECT_NAME=${PROJECT_NAME} -P ${IGNITION_CMAKE_DIR}/IgnGenerateVersionInfo.cmake ) endfunction() function(ign_add_benchmarks) cmake_parse_arguments(BENCHMARK "" "" "SOURCES" ${ARGN}) if(NOT BUILD_TESTING) return() endif() find_package(benchmark) if(NOT benchmark_FOUND) message(WARNING "Unable to find google benchmark (libbenchmark-dev). Disabling benchmarks.") return() endif() ign_build_executables( PREFIX "BENCHMARK_" SOURCES ${BENCHMARK_SOURCES} LIB_DEPS benchmark::benchmark EXEC_LIST BENCHMARK_TARGETS ) set(BENCHMARK_TARGETS_LIST "") foreach(benchmark ${BENCHMARK_TARGETS}) list(APPEND BENCHMARK_TARGETS_LIST "$") endforeach() ign_add_version_info_target() file(GENERATE OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/benchmark_targets" CONTENT "${BENCHMARK_TARGETS_LIST}") add_custom_target( run_benchmarks COMMAND python3 ${IGNITION_CMAKE_BENCHMARK_DIR}/run_benchmarks.py --project-name ${PROJECT_NAME} --version-file ${CMAKE_CURRENT_BINARY_DIR}/version_info.json --benchmark-targets ${CMAKE_CURRENT_BINARY_DIR}/benchmark_targets --results-root ${CMAKE_BINARY_DIR}/benchmark_results ) add_dependencies(run_benchmarks ${BENCHMARK_TARGETS} version_info_target) endfunction() ign-cmake-ignition-cmake2_2.10.0/cmake/FindGTS.cmake0000664000175000017500000000547414160533245021746 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find GNU Triangulation Surface Library if (NOT WIN32) # Configuration using pkg-config modules include(IgnPkgConfig) ign_pkg_check_modules(GTS gts) else() # true by default, change to false when a failure appears set(GTS_FOUND true) # 1. look for GTS headers find_path(GTS_INCLUDE_DIRS gts.h hints ${CMAKE_FIND_ROOT_PATH} paths ${CMAKE_FIND_ROOT_PATH} doc "GTS header include dir" path_suffixes include ) if (GTS_INCLUDE_DIRS) if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for gts.h gtsconfig.h - found") endif() else() if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for gts.h gtsconfig.h - not found") endif() set(GTS_FOUND false) endif() mark_as_advanced(GTS_INCLUDE_DIRS) # 2. look for GTS libraries find_library(GTS_LIBRARIES gts) mark_as_advanced(GTS_LIBRARIES) if (GTS_LIBRARIES) if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for gts library - found") endif() else() if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for gts library - not found") endif() set (GTS_FOUND false) endif() # 2.1 Need glib library find_library(GLIB_LIBRARY glib-2.0) if (NOT GLIB_LIBRARY) if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for glib library - not found") endif() else() if(NOT GTS_FIND_QUIETLY) message(STATUS "Looking for glib library - found") endif() endif() find_path(GLIB_INCLUDE_DIR NAMES glib.h PATH_SUFFIXES glib-2.0) if (GLIB_INCLUDE_DIR) list(APPEND GTS_INCLUDE_DIRS "${GLIB_INCLUDE_DIR}") endif() find_path(GLIBCONFIG_INCLUDE_DIR NAMES glibconfig.h PATH_SUFFIXES lib/glib-2.0/include) if (GLIBCONFIG_INCLUDE_DIR) list(APPEND GTS_INCLUDE_DIRS "${GLIBCONFIG_INCLUDE_DIR}") endif() list(APPEND GTS_LIBRARIES "${GLIB_LIBRARY}") if (GTS_FOUND) # We need to manually specify the pkgconfig entry (and type of entry), # because ign_pkg_check_modules does not work for it. include(IgnPkgConfig) ign_pkg_config_library_entry(GTS gts) include(IgnImportTarget) ign_import_target(GTS) endif() endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindIgnURDFDOM.cmake0000664000175000017500000000331014160533245023032 0ustar jriverojrivero# # Copyright (C) 2021 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # Prefer pkg-config over cmake if possible since version checking is not working # on urdfdom series from 1.x to 3.0.0 (at least) include(IgnPkgConfig) if(PKG_CONFIG_FOUND) if (IgnURDFDOM_FIND_VERSION) set(signature "urdfdom >= ${IgnURDFDOM_FIND_VERSION}") else() set(signature "urdfdom") endif() ign_pkg_check_modules(IgnURDFDOM "${signature}") else() message(VERBOSE "Unable to find pkg-config in the system, fallback to use CMake") endif() if(NOT IgnURDFDOM_FOUND) if(IgnURDFDOM_FIND_VERSION) set(find_version VERSION ${IgnURDFDOM_FIND_VERSION}) else() set(find_version "") endif() # NOTE: urdfdom cmake does not support version checking ign_find_package(urdfdom ${find_version} QUIET) if (urdfdom_FOUND) add_library(IgnURDFDOM::IgnURDFDOM INTERFACE IMPORTED) target_link_libraries(IgnURDFDOM::IgnURDFDOM INTERFACE urdfdom::urdfdom_model urdfdom::urdfdom_world urdfdom::urdfdom_sensor urdfdom::urdfdom_model_state ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(IgnURDFDOM DEFAULT_MSG) endif() endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindFreeImage.cmake0000664000175000017500000001120214160533245023117 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find FreeImage # Grab the version numbers requested by the call to find_package(~) set(major_version ${FreeImage_FIND_VERSION_MAJOR}) set(minor_version ${FreeImage_FIND_VERSION_MINOR}) # Set the full version number set(full_version ${major_version}.${minor_version}) if (NOT WIN32) include(IgnPkgConfig) ign_pkg_config_library_entry(FreeImage freeimage) # If we don't have PkgConfig, or if PkgConfig failed, then do a manual search if(NOT FreeImage_FOUND) find_path(FreeImage_INCLUDE_DIRS FreeImage.h) if(NOT FreeImage_INCLUDE_DIRS) if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Looking for FreeImage.h - not found") message(STATUS "Missing: Unable to find FreeImage.h") endif() else(NOT FreeImage_INCLUDE_DIRS) # Check the FreeImage header for the right version set(testFreeImageSource ${CMAKE_CURRENT_BINARY_DIR}/CMakeTmp/test_freeimage.c) set(FreeImage_test_output "") set(FreeImage_compile_output "") file(WRITE ${testFreeImageSource} "#include \nint main () { if (FREEIMAGE_MAJOR_VERSION >= ${major_version} && FREEIMAGE_MINOR_VERSION >= ${minor_version}) return 1; else return 0;} \n") try_run(FREEIMAGE_RUNS FREEIMAGE_COMPILES ${CMAKE_CURRENT_BINARY_DIR} ${testFreeImageSource} CMAKE_FLAGS -DINCLUDE_DIRECTORIES=${FreeImage_INCLUDE_DIRS} RUN_OUTPUT_VARIABLE FreeImage_test_output COMPILE_OUTPUT_VARIABLE FreeImage_compile_output) if(NOT FREEIMAGE_COMPILES) if(NOT FreeImage_FIND_QUIETLY) message(STATUS "FreeImage test failed to compile - This may indicate a build system bug") endif() return() endif(NOT FREEIMAGE_COMPILES) if(NOT FREEIMAGE_RUNS) if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Invalid FreeImage Version. Requires ${major_version}.${minor_version}") endif() endif(NOT FREEIMAGE_RUNS) endif(NOT FreeImage_INCLUDE_DIRS) mark_as_advanced(FreeImage_INCLUDE_DIRS) find_library(FreeImage_LIBRARIES NAMES freeimage FreeImage) if(FreeImage_LIBRARIES) set(FreeImage_FOUND true) else() if(NOT FreeImage_FIND_QUIELTY) message(STATUS "Missing: Unable to find libfreeimage") endif() endif(FreeImage_LIBRARIES) mark_as_advanced(FreeImage_LIBRARIES) endif() if(FreeImage_FOUND) # Create the imported target for FreeImage if we found it include(IgnImportTarget) ign_import_target(FreeImage) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( FreeImage REQUIRED_VARS FreeImage_FOUND) else() # true by default, change to false when a failure appears set(FreeImage_FOUND true) # 1. look for FreeImage headers find_path(FreeImage_INCLUDE_DIRS FreeImage.h hints ${CMAKE_FIND_ROOT_PATH} paths ${CMAKE_FIND_ROOT_PATH} doc "FreeImage header include dir" path_suffixes include ) if (FreeImage_INCLUDE_DIRS) if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Looking for FreeImage.h FreeImageconfig.h - found") endif() else() if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Looking for FreeImage.h FreeImageconfig.h - not found") endif() set(FreeImage_FOUND false) endif() mark_as_advanced(FreeImage_INCLUDE_DIRS) # 2. look for FreeImage libraries find_library(FreeImage_LIBRARIES FreeImage) mark_as_advanced(FreeImage_LIBRARIES) if (FreeImage_LIBRARIES) if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Looking for FreeImage library - found") endif() else() if(NOT FreeImage_FIND_QUIETLY) message(STATUS "Looking for FreeImage library - not found") endif() set (FreeImage_FOUND false) endif() if (FreeImage_FOUND) include(IgnPkgConfig) ign_pkg_config_library_entry(FreeImage "FreeImage") include(IgnImportTarget) ign_import_target(FreeImage) endif() endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindCPPZMQ.cmake0000664000175000017500000000415514160533245022316 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # #=============================================================================== # Find cppzmq # # Usage of this module as follows: # # find_package(CPPZMQ) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # CPPZMQ_HEADER_PATH Set this variable to the location of the zmp.hpp # header file if the module has problems finding it. # ZeroMQ_INCLUDE_DIRS Set this variable to the include directories of # ZeroMQ if the module has problems finding # the proper installation path. # # Variables defined by this module: # # CPPZMQ_FOUND System has CPPZMQ header # CPPZMQ_INCLUDE_DIRS The location of zmq.hpp header # If we cannot find the header, we will switch this to false set(CPPZMQ_FOUND true) # Search for the header find_path(CPPZMQ_INCLUDE_DIRS zmq.hpp PATHS ${ZeroMQ_INCLUDE_DIRS} ${CPPZMQ_HEADER_PATH}) mark_as_advanced(CPPZMQ_INCLUDE_DIRS) if(NOT CPPZMQ_INCLUDE_DIRS) set(CPPZMQ_FOUND false) endif() if(CPPZMQ_FOUND) include(IgnImportTarget) # Since this is a header-only library, we should import it as an INTERFACE # target. ign_import_target(CPPZMQ INTERFACE) # Now, to use the CPPZMQ headers, you should call # target_link_libraries( CPPZMQ::CPPZMQ) instead of using # target_include_directories(~) endif() ign-cmake-ignition-cmake2_2.10.0/cmake/cmake_uninstall.cmake.in0000664000175000017500000000202314160533245024251 0ustar jriverojriveroif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") message(FATAL_ERROR "Cannot find install manifest: '@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt'") endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) string(REGEX REPLACE "\n" ";" files "${files}") foreach(file ${files}) message(STATUS "Uninstalling '$ENV{DESTDIR}${file}'") if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") exec_program( "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" OUTPUT_VARIABLE rm_out RETURN_VALUE rm_retval ) if(NOT "${rm_retval}" STREQUAL 0) message(FATAL_ERROR "Problem when removing '$ENV{DESTDIR}${file}'") endif(NOT "${rm_retval}" STREQUAL 0) else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") message(STATUS "File '$ENV{DESTDIR}${file}' does not exist.") endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") endforeach(file) ign-cmake-ignition-cmake2_2.10.0/cmake/ignition-all-config.cmake.in0000664000175000017500000000365414160533245024744 0ustar jriverojrivero# - Config to retrieve all components of the @PKG_NAME@ package # # This should only be invoked by @PKG_NAME@-config.cmake. # # To retrieve this meta-package, use: # find_package(@PKG_NAME@ COMPONENTS all) # # This creates the target @ign_namespace@all which will link to all known # components of @PKG_NAME@, including the core library. # # This also creates the variable @PKG_NAME@_ALL_LIBRARIES # ################################################################################ cmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) if(@PKG_NAME@_ALL_CONFIG_INCLUDED) return() endif() set(@PKG_NAME@_ALL_CONFIG_INCLUDED TRUE) if(NOT @all_pkg_name@_FIND_QUIETLY) message(STATUS "Looking for all libraries of @PKG_NAME@ -- found version @PROJECT_VERSION_FULL@") endif() @PACKAGE_INIT@ # Get access to the find_dependency utility include(CMakeFindDependencyMacro) # Find the core library find_dependency(@PKG_NAME@ @PROJECT_VERSION_FULL_NO_SUFFIX@ EXACT) # Find the component libraries @find_all_pkg_components@ if(NOT TARGET @import_target_name@) include("${CMAKE_CURRENT_LIST_DIR}/@target_output_filename@") add_library(@simple_import_name@ INTERFACE IMPORTED) set_target_properties(@simple_import_name@ PROPERTIES INTERFACE_LINK_LIBRARIES "@import_target_name@") endif() # Create the "requested" target if it does not already exist if(NOT TARGET @ign_namespace@requested) add_library(@ign_namespace@requested INTERFACE IMPORTED) endif() # Link the "all" target to the "requested" target get_target_property(ign_requested_components @ign_namespace@requested INTERFACE_LINK_LIBRARIES) if(NOT ign_requested_components) set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "@import_target_name@") else() set_target_properties(@ign_namespace@requested PROPERTIES INTERFACE_LINK_LIBRARIES "${ign_requested_components};@import_target_name@") endif() set(@PKG_NAME@_ALL_LIBRARIES @import_target_name@) ign-cmake-ignition-cmake2_2.10.0/cmake/IgnRonn2Man.cmake0000664000175000017500000000375414160533245022577 0ustar jriverojrivero# # Based on work of Emmanuel Roullit # Copyright 2009, 2012 Emmanuel Roullit. # Subject to the GPL, version 2. # # 2017-09-13 # - Tweaked macro name to avoid name collisions # MACRO(IGN_ADD_MANPAGE_TARGET) # It is not possible add a dependency to target 'install' # Run hard-coded 'make man' when 'make install' is invoked INSTALL(CODE "EXECUTE_PROCESS(COMMAND $(MAKE) man)") ADD_CUSTOM_TARGET(man) ENDMACRO(IGN_ADD_MANPAGE_TARGET) FIND_PROGRAM(RONN ronn) FIND_PROGRAM(GZIP gzip) IF (NOT RONN OR NOT GZIP) IF (NOT RONN) IGN_BUILD_WARNING ("ronn not found, manpages won't be generated") ENDIF(NOT RONN) IF (NOT GZIP) IGN_BUILD_WARNING ("gzip not found, manpages won't be generated") ENDIF(NOT GZIP) # empty macro MACRO(manpage MANFILE) ENDMACRO(manpage) SET (MANPAGES_SUPPORT FALSE) ELSE (NOT RONN OR NOT GZIP) MESSAGE (STATUS "Looking for ronn to generate manpages - found") SET (MANPAGES_SUPPORT TRUE) MACRO(manpage RONNFILE SECTION) SET(RONNFILE_FULL_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${RONNFILE}) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} DEPENDS ${RONNFILE} COMMAND ${RONN} ARGS -r --pipe ${RONNFILE_FULL_PATH}.${SECTION}.ronn > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} ) ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} COMMAND ${GZIP} -c ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION} > ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz ) SET(MANPAGE_TARGET "man-${RONNFILE}") ADD_CUSTOM_TARGET(${MANPAGE_TARGET} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz) ADD_DEPENDENCIES(man ${MANPAGE_TARGET}) INSTALL( FILES ${CMAKE_CURRENT_BINARY_DIR}/${RONNFILE}.${SECTION}.gz DESTINATION share/man/man${SECTION} ) ENDMACRO(manpage RONNFILE SECTION) ENDIF(NOT RONN OR NOT GZIP) ign-cmake-ignition-cmake2_2.10.0/cmake/FindZeroMQ.cmake0000664000175000017500000000644214160533245022462 0ustar jriverojrivero##============================================================================= # # CMake - Cross Platform Makefile Generator # Copyright 2000-2011 Kitware, Inc., Insight Software Consortium # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # * Neither the names of Kitware, Inc., the Insight Software Consortium, # nor the names of their contributors may be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # Modified by Jose Luis Rivero # ##============================================================================= # - Try to find ZeroMQ headers and libraries # # Usage of this module as follows: # # find_package(ZeroMQ) # # Variables used by this module, they can change the default behaviour and need # to be set before calling find_package: # # ZeroMQ_ROOT_DIR Set this variable to the root installation of # ZeroMQ if the module has problems finding # the proper installation path. # # Variables defined by this module: # # ZEROMQ_FOUND System has ZeroMQ libs/headers # ZeroMQ_LIBRARIES The ZeroMQ libraries # ZeroMQ_INCLUDE_DIRS The location of ZeroMQ headers include(IgnPkgConfig) # We initialize this variable to the default target name set(ZeroMQ_TARGET ZeroMQ::ZeroMQ) find_package(ZeroMQ ${ZeroMQ_FIND_VERSION} QUIET CONFIG) if (ZeroMQ_FOUND) # ZeroMQ's cmake script imports its own target, so we'll # overwrite the default with the name of theirs. In the # future, we should be able to use a target alias instead. set(ZeroMQ_TARGET libzmq) # Make sure to fill out the pkg-config information before quitting ign_pkg_config_entry(ZeroMQ "libzmq >= ${ZeroMQ_FIND_VERSION}") return() endif() if (UNIX) if(NOT ZeroMQ_FIND_QUIETLY) message(STATUS "Config-file not installed for ZeroMQ -- checking for pkg-config") endif() ign_pkg_check_modules(ZeroMQ "libzmq >= ${ZeroMQ_FIND_VERSION}") endif() ign-cmake-ignition-cmake2_2.10.0/cmake/FindAVUTIL.cmake0000664000175000017500000000211514160533245022302 0ustar jriverojrivero#=============================================================================== # Copyright (C) 2017 Open Source Robotics Foundation # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ######################################## # Find avutil include(IgnPkgConfig) ign_pkg_check_modules_quiet(AVUTIL libavutil) if(NOT AVUTIL_FOUND) include(IgnManualSearch) ign_manual_search(AVUTIL HEADER_NAMES "libavutil/avutil.h" LIBRARY_NAMES "avutil") endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args( AVUTIL REQUIRED_VARS AVUTIL_FOUND) ign-cmake-ignition-cmake2_2.10.0/cmake/upload_doc.sh.in0000664000175000017500000000252314160533245022550 0ustar jriverojrivero#!/bin/sh echo "Usage: sh upload_doc.sh [y/n]" echo " Optional [y/n] argument indicates whether to upload the docs to S3 automatically." # Check if the node was configured to use s3cmd # This is done by running s3cmd --configure if [ ! -f "${HOME}/.s3cfg" ]; then echo "No $HOME/.s3cfg file found. Please config the software first in your system" exit 1 fi # Make documentation if not build if [ ! -f "@CMAKE_BINARY_DIR@/doxygen/html/index.html" ]; then make doc if [ ! -f "@CMAKE_BINARY_DIR@/doxygen/html/index.html" ]; then echo "Documentation not present. Install doxygen, and run `make doc` in the build directory" exit 1 fi fi # Dry run s3cmd sync --dry-run @CMAKE_BINARY_DIR@/doxygen/html/ s3://ignitionrobotics.org/api/@IGN_DESIGNATION@/@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@/ -v if [ -z "$1" ]; then echo -n "Upload (Y/n)? " read ans else ans=$1 fi if [ "$ans" = "n" ] || [ "$ans" = "N" ]; then exit 1 else s3cmd sync @CMAKE_BINARY_DIR@/doxygen/html/ s3://ignitionrobotics.org/api/@IGN_DESIGNATION@/@PROJECT_VERSION_MAJOR@.@PROJECT_VERSION_MINOR@/ -v echo "WARNING" echo " A CloudFront invalidation is required. Run the following command with the appropriate \$CLOUDFRONT_DISTRIBUTION_ID:\n" echo " aws cloudfront create-invalidation --distribution-id \$CLOUDFRONT_DISTRIBUTION_ID --paths '/*'" fi ign-cmake-ignition-cmake2_2.10.0/tutorials.md.in0000664000175000017500000000123014160533245021365 0ustar jriverojrivero\page tutorials Tutorials Welcome to the Ignition @IGN_DESIGNATION_CAP@ tutorials. These tutorials will guide you through the process of understanding the capabilities of the Ignition @IGN_DESIGNATION_CAP@ library and how to use the library effectively. **The tutorials** 1. \subpage install "Installation" 1. \subpage developingwithcmake "Developing with Ignition CMake" ## License The code associated with this documentation is licensed under an [Apache 2.0 License](https://www.apache.org/licenses/LICENSE-2.0). This documentation is licensed under a [Creative Commons Attribution 4.0 International License](http://creativecommons.org/licenses/by/4.0/). ign-cmake-ignition-cmake2_2.10.0/codecheck/0000775000175000017500000000000014160533245020324 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/codecheck/namespace_AZ.rule0000664000175000017500000000040614160533245023543 0ustar jriverojrivero :: _[A-Z] _AZnaming warning Identifier that starts with underscore and then a capital letter is reserved. ign-cmake-ignition-cmake2_2.10.0/codecheck/header_guard.rule0000664000175000017500000000044514160533245023632 0ustar jriverojrivero define #define _[A-Z] _AZdefine warning Definitions should not start with underscore and then a capital letter. ign-cmake-ignition-cmake2_2.10.0/codecheck/cpplint.py0000664000175000017500000100113514160533245022350 0ustar jriverojrivero#!/usr/bin/env python # # Copyright (c) 2009 Google Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are # met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following disclaimer # in the documentation and/or other materials provided with the # distribution. # * Neither the name of Google Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # Imported from https://github.com/cpplint/cpplint: # https://github.com/cpplint/cpplint/blob/0f2319741f3407d8638cdc7c41e4fc9bad217f68/cpplint.py """Does google-lint on c++ files. The goal of this script is to identify places in the code that *may* be in non-compliance with google style. It does not attempt to fix up these problems -- the point is to educate. It does also not attempt to find all problems, or to ensure that everything it does find is legitimately a problem. In particular, we can get very confused by /* and // inside strings! We do a small hack, which is to ignore //'s with "'s after them on the same line, but it is far from perfect (in either direction). """ import codecs import copy import getopt import glob import itertools import math # for log import os import re import sre_compile import string import sys import sysconfig import unicodedata import xml.etree.ElementTree # if empty, use defaults _valid_extensions = set([]) __VERSION__ = '1.5.4' try: xrange # Python 2 except NameError: # -- pylint: disable=redefined-builtin xrange = range # Python 3 _USAGE = """ Syntax: cpplint.py [--verbose=#] [--output=emacs|eclipse|vs7|junit|sed|gsed] [--filter=-x,+y,...] [--counting=total|toplevel|detailed] [--root=subdir] [--repository=path] [--linelength=digits] [--headers=x,y,...] [--recursive] [--exclude=path] [--extensions=hpp,cpp,...] [--includeorder=default|standardcfirst] [--quiet] [--version] [file] ... Style checker for C/C++ source files. This is a fork of the Google style checker with minor extensions. The style guidelines this tries to follow are those in https://google.github.io/styleguide/cppguide.html Every problem is given a confidence score from 1-5, with 5 meaning we are certain of the problem, and 1 meaning it could be a legitimate construct. This will miss some errors, and is not a substitute for a code review. To suppress false-positive errors of a certain category, add a 'NOLINT(category)' comment to the line. NOLINT or NOLINT(*) suppresses errors of all categories on that line. The files passed in will be linted; at least one file must be provided. Default linted extensions are %s. Other file types will be ignored. Change the extensions with the --extensions flag. Flags: output=emacs|eclipse|vs7|junit|sed|gsed By default, the output is formatted to ease emacs parsing. Visual Studio compatible output (vs7) may also be used. Further support exists for eclipse (eclipse), and JUnit (junit). XML parsers such as those used in Jenkins and Bamboo may also be used. The sed format outputs sed commands that should fix some of the errors. Note that this requires gnu sed. If that is installed as gsed on your system (common e.g. on macOS with homebrew) you can use the gsed output format. Sed commands are written to stdout, not stderr, so you should be able to pipe output straight to a shell to run the fixes. verbose=# Specify a number 0-5 to restrict errors to certain verbosity levels. Errors with lower verbosity levels have lower confidence and are more likely to be false positives. quiet Don't print anything if no errors are found. filter=-x,+y,... Specify a comma-separated list of category-filters to apply: only error messages whose category names pass the filters will be printed. (Category names are printed with the message and look like "[whitespace/indent]".) Filters are evaluated left to right. "-FOO" and "FOO" means "do not print categories that start with FOO". "+FOO" means "do print categories that start with FOO". Examples: --filter=-whitespace,+whitespace/braces --filter=whitespace,runtime/printf,+runtime/printf_format --filter=-,+build/include_what_you_use To see a list of all the categories used in cpplint, pass no arg: --filter= counting=total|toplevel|detailed The total number of errors found is always printed. If 'toplevel' is provided, then the count of errors in each of the top-level categories like 'build' and 'whitespace' will also be printed. If 'detailed' is provided, then a count is provided for each category like 'build/class'. repository=path The top level directory of the repository, used to derive the header guard CPP variable. By default, this is determined by searching for a path that contains .git, .hg, or .svn. When this flag is specified, the given path is used instead. This option allows the header guard CPP variable to remain consistent even if members of a team have different repository root directories (such as when checking out a subdirectory with SVN). In addition, users of non-mainstream version control systems can use this flag to ensure readable header guard CPP variables. Examples: Assuming that Alice checks out ProjectName and Bob checks out ProjectName/trunk and trunk contains src/chrome/ui/browser.h, then with no --repository flag, the header guard CPP variable will be: Alice => TRUNK_SRC_CHROME_BROWSER_UI_BROWSER_H_ Bob => SRC_CHROME_BROWSER_UI_BROWSER_H_ If Alice uses the --repository=trunk flag and Bob omits the flag or uses --repository=. then the header guard CPP variable will be: Alice => SRC_CHROME_BROWSER_UI_BROWSER_H_ Bob => SRC_CHROME_BROWSER_UI_BROWSER_H_ root=subdir The root directory used for deriving header guard CPP variable. This directory is relative to the top level directory of the repository which by default is determined by searching for a directory that contains .git, .hg, or .svn but can also be controlled with the --repository flag. If the specified directory does not exist, this flag is ignored. Examples: Assuming that src is the top level directory of the repository (and cwd=top/src), the header guard CPP variables for src/chrome/browser/ui/browser.h are: No flag => CHROME_BROWSER_UI_BROWSER_H_ --root=chrome => BROWSER_UI_BROWSER_H_ --root=chrome/browser => UI_BROWSER_H_ --root=.. => SRC_CHROME_BROWSER_UI_BROWSER_H_ linelength=digits This is the allowed line length for the project. The default value is 80 characters. Examples: --linelength=120 recursive Search for files to lint recursively. Each directory given in the list of files to be linted is replaced by all files that descend from that directory. Files with extensions not in the valid extensions list are excluded. exclude=path Exclude the given path from the list of files to be linted. Relative paths are evaluated relative to the current directory and shell globbing is performed. This flag can be provided multiple times to exclude multiple files. Examples: --exclude=one.cc --exclude=src/*.cc --exclude=src/*.cc --exclude=test/*.cc extensions=extension,extension,... The allowed file extensions that cpplint will check Examples: --extensions=%s includeorder=default|standardcfirst For the build/include_order rule, the default is to blindly assume angle bracket includes with file extension are c-system-headers (default), even knowing this will have false classifications. The default is established at google. standardcfirst means to instead use an allow-list of known c headers and treat all others as separate group of "other system headers". The C headers included are those of the C-standard lib and closely related ones. headers=x,y,... The header extensions that cpplint will treat as .h in checks. Values are automatically added to --extensions list. (by default, only files with extensions %s will be assumed to be headers) Examples: --headers=%s --headers=hpp,hxx --headers=hpp cpplint.py supports per-directory configurations specified in CPPLINT.cfg files. CPPLINT.cfg file can contain a number of key=value pairs. Currently the following options are supported: set noparent filter=+filter1,-filter2,... exclude_files=regex linelength=80 root=subdir headers=x,y,... "set noparent" option prevents cpplint from traversing directory tree upwards looking for more .cfg files in parent directories. This option is usually placed in the top-level project directory. The "filter" option is similar in function to --filter flag. It specifies message filters in addition to the |_DEFAULT_FILTERS| and those specified through --filter command-line flag. "exclude_files" allows to specify a regular expression to be matched against a file name. If the expression matches, the file is skipped and not run through the linter. "linelength" allows to specify the allowed line length for the project. The "root" option is similar in function to the --root flag (see example above). Paths are relative to the directory of the CPPLINT.cfg. The "headers" option is similar in function to the --headers flag (see example above). CPPLINT.cfg has an effect on files in the same directory and all sub-directories, unless overridden by a nested configuration file. Example file: filter=-build/include_order,+build/include_alpha exclude_files=.*\\.cc The above example disables build/include_order warning and enables build/include_alpha as well as excludes all .cc from being processed by linter, in the current directory (where the .cfg file is located) and all sub-directories. """ # We categorize each error message we print. Here are the categories. # We want an explicit list so we can list them all in cpplint --filter=. # If you add a new error message with a new category, add it to the list # here! cpplint_unittest.py should tell you if you forget to do this. _ERROR_CATEGORIES = [ 'build/class', 'build/c++11', 'build/c++14', 'build/c++tr1', 'build/deprecated', 'build/endif_comment', 'build/explicit_make_pair', 'build/forward_decl', 'build/header_guard', 'build/include', 'build/include_subdir', 'build/include_alpha', 'build/include_order', 'build/include_what_you_use', 'build/namespaces_headers', 'build/namespaces_literals', 'build/namespaces', 'build/printf_format', 'build/storage_class', 'legal/copyright', 'readability/alt_tokens', 'readability/braces', 'readability/casting', 'readability/check', 'readability/constructors', 'readability/fn_size', 'readability/inheritance', 'readability/multiline_comment', 'readability/multiline_string', 'readability/namespace', 'readability/nolint', 'readability/nul', 'readability/strings', 'readability/todo', 'readability/utf8', 'runtime/arrays', 'runtime/casting', 'runtime/explicit', 'runtime/int', 'runtime/init', 'runtime/invalid_increment', 'runtime/member_string_references', 'runtime/memset', 'runtime/indentation_namespace', 'runtime/operator', 'runtime/printf', 'runtime/printf_format', 'runtime/references', 'runtime/string', 'runtime/threadsafe_fn', 'runtime/vlog', 'whitespace/blank_line', 'whitespace/braces', 'whitespace/comma', 'whitespace/comments', 'whitespace/empty_conditional_body', 'whitespace/empty_if_body', 'whitespace/empty_loop_body', 'whitespace/end_of_line', 'whitespace/ending_newline', 'whitespace/forcolon', 'whitespace/indent', 'whitespace/line_length', 'whitespace/newline', 'whitespace/operators', 'whitespace/parens', 'whitespace/semicolon', 'whitespace/tab', 'whitespace/todo', ] # keywords to use with --outputs which generate stdout for machine processing _MACHINE_OUTPUTS = [ 'junit', 'sed', 'gsed' ] # These error categories are no longer enforced by cpplint, but for backwards- # compatibility they may still appear in NOLINT comments. _LEGACY_ERROR_CATEGORIES = [ 'readability/streams', 'readability/function', ] # The default state of the category filter. This is overridden by the --filter= # flag. By default all errors are on, so only add here categories that should be # off by default (i.e., categories that must be enabled by the --filter= flags). # All entries here should start with a '-' or '+', as in the --filter= flag. _DEFAULT_FILTERS = [ '-build/c++11', '-build/header_guard', '-build/include_alpha', '-build/include_order', '-build/include_subdir', '-build/namespaces', '-readability/namespace', '-runtime/indentation_namespace', '-runtime/references', '-whitespace/blank_line', '-whitespace/braces', '-whitespace/indent', '-whitespace/newline', '-whitespace/parens', ] # The default list of categories suppressed for C (not C++) files. _DEFAULT_C_SUPPRESSED_CATEGORIES = [ 'readability/casting', ] # The default list of categories suppressed for Linux Kernel files. _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES = [ 'whitespace/tab', ] # We used to check for high-bit characters, but after much discussion we # decided those were OK, as long as they were in UTF-8 and didn't represent # hard-coded international strings, which belong in a separate i18n file. # C++ headers _CPP_HEADERS = frozenset([ # Legacy 'algobase.h', 'algo.h', 'alloc.h', 'builtinbuf.h', 'bvector.h', 'complex.h', 'defalloc.h', 'deque.h', 'editbuf.h', 'fstream.h', 'function.h', 'hash_map', 'hash_map.h', 'hash_set', 'hash_set.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip.h', 'iostream.h', 'istream.h', 'iterator.h', 'list.h', 'map.h', 'multimap.h', 'multiset.h', 'ostream.h', 'pair.h', 'parsestream.h', 'pfstream.h', 'procbuf.h', 'pthread_alloc', 'pthread_alloc.h', 'rope', 'rope.h', 'ropeimpl.h', 'set.h', 'slist', 'slist.h', 'stack.h', 'stdiostream.h', 'stl_alloc.h', 'stl_relops.h', 'streambuf.h', 'stream.h', 'strfile.h', 'strstream.h', 'tempbuf.h', 'tree.h', 'type_traits.h', 'vector.h', # 17.6.1.2 C++ library headers 'algorithm', 'array', 'atomic', 'bitset', 'chrono', 'codecvt', 'complex', 'condition_variable', 'deque', 'exception', 'forward_list', 'fstream', 'functional', 'future', 'initializer_list', 'iomanip', 'ios', 'iosfwd', 'iostream', 'istream', 'iterator', 'limits', 'list', 'locale', 'map', 'memory', 'mutex', 'new', 'numeric', 'ostream', 'queue', 'random', 'ratio', 'regex', 'scoped_allocator', 'set', 'sstream', 'stack', 'stdexcept', 'streambuf', 'string', 'strstream', 'system_error', 'thread', 'tuple', 'typeindex', 'typeinfo', 'type_traits', 'unordered_map', 'unordered_set', 'utility', 'valarray', 'vector', # 17.6.1.2 C++14 headers 'shared_mutex', # 17.6.1.2 C++17 headers 'any', 'charconv', 'codecvt', 'execution', 'filesystem', 'memory_resource', 'optional', 'string_view', 'variant', # 17.6.1.2 C++ headers for C library facilities 'cassert', 'ccomplex', 'cctype', 'cerrno', 'cfenv', 'cfloat', 'cinttypes', 'ciso646', 'climits', 'clocale', 'cmath', 'csetjmp', 'csignal', 'cstdalign', 'cstdarg', 'cstdbool', 'cstddef', 'cstdint', 'cstdio', 'cstdlib', 'cstring', 'ctgmath', 'ctime', 'cuchar', 'cwchar', 'cwctype', ]) # C headers _C_HEADERS = frozenset([ # System C headers 'assert.h', 'complex.h', 'ctype.h', 'errno.h', 'fenv.h', 'float.h', 'inttypes.h', 'iso646.h', 'limits.h', 'locale.h', 'math.h', 'setjmp.h', 'signal.h', 'stdalign.h', 'stdarg.h', 'stdatomic.h', 'stdbool.h', 'stddef.h', 'stdint.h', 'stdio.h', 'stdlib.h', 'stdnoreturn.h', 'string.h', 'tgmath.h', 'threads.h', 'time.h', 'uchar.h', 'wchar.h', 'wctype.h', # additional POSIX C headers 'aio.h', 'arpa/inet.h', 'cpio.h', 'dirent.h', 'dlfcn.h', 'fcntl.h', 'fmtmsg.h', 'fnmatch.h', 'ftw.h', 'glob.h', 'grp.h', 'iconv.h', 'langinfo.h', 'libgen.h', 'monetary.h', 'mqueue.h', 'ndbm.h', 'net/if.h', 'netdb.h', 'netinet/in.h', 'netinet/tcp.h', 'nl_types.h', 'poll.h', 'pthread.h', 'pwd.h', 'regex.h', 'sched.h', 'search.h', 'semaphore.h', 'setjmp.h', 'signal.h', 'spawn.h', 'strings.h', 'stropts.h', 'syslog.h', 'tar.h', 'termios.h', 'trace.h', 'ulimit.h', 'unistd.h', 'utime.h', 'utmpx.h', 'wordexp.h', # additional GNUlib headers 'a.out.h', 'aliases.h', 'alloca.h', 'ar.h', 'argp.h', 'argz.h', 'byteswap.h', 'crypt.h', 'endian.h', 'envz.h', 'err.h', 'error.h', 'execinfo.h', 'fpu_control.h', 'fstab.h', 'fts.h', 'getopt.h', 'gshadow.h', 'ieee754.h', 'ifaddrs.h', 'libintl.h', 'mcheck.h', 'mntent.h', 'obstack.h', 'paths.h', 'printf.h', 'pty.h', 'resolv.h', 'shadow.h', 'sysexits.h', 'ttyent.h', # Additional linux glibc headers 'dlfcn.h', 'elf.h', 'features.h', 'gconv.h', 'gnu-versions.h', 'lastlog.h', 'libio.h', 'link.h', 'malloc.h', 'memory.h', 'netash/ash.h', 'netatalk/at.h', 'netax25/ax25.h', 'neteconet/ec.h', 'netipx/ipx.h', 'netiucv/iucv.h', 'netpacket/packet.h', 'netrom/netrom.h', 'netrose/rose.h', 'nfs/nfs.h', 'nl_types.h', 'nss.h', 're_comp.h', 'regexp.h', 'sched.h', 'sgtty.h', 'stab.h', 'stdc-predef.h', 'stdio_ext.h', 'syscall.h', 'termio.h', 'thread_db.h', 'ucontext.h', 'ustat.h', 'utmp.h', 'values.h', 'wait.h', 'xlocale.h', # Hardware specific headers 'arm_neon.h', 'emmintrin.h', 'xmmintin.h', ]) # Folders of C libraries so commonly used in C++, # that they have parity with standard C libraries. C_STANDARD_HEADER_FOLDERS = frozenset([ # standard C library "sys", # glibc for linux "arpa", "asm-generic", "bits", "gnu", "net", "netinet", "protocols", "rpc", "rpcsvc", "scsi", # linux kernel header "drm", "linux", "misc", "mtd", "rdma", "sound", "video", "xen", ]) # Type names _TYPES = re.compile( r'^(?:' # [dcl.type.simple] r'(char(16_t|32_t)?)|wchar_t|' r'bool|short|int|long|signed|unsigned|float|double|' # [support.types] r'(ptrdiff_t|size_t|max_align_t|nullptr_t)|' # [cstdint.syn] r'(u?int(_fast|_least)?(8|16|32|64)_t)|' r'(u?int(max|ptr)_t)|' r')$') # These headers are excluded from [build/include] and [build/include_order] # checks: # - Anything not following google file name conventions (containing an # uppercase character, such as Python.h or nsStringAPI.h, for example). # - Lua headers. _THIRD_PARTY_HEADERS_PATTERN = re.compile( r'^(?:[^/]*[A-Z][^/]*\.h|lua\.h|lauxlib\.h|lualib\.h)$') # Pattern for matching FileInfo.BaseName() against test file name _test_suffixes = ['_test', '_regtest', '_unittest'] _TEST_FILE_SUFFIX = '(' + '|'.join(_test_suffixes) + r')$' # Pattern that matches only complete whitespace, possibly across multiple lines. _EMPTY_CONDITIONAL_BODY_PATTERN = re.compile(r'^\s*$', re.DOTALL) # Assertion macros. These are defined in base/logging.h and # testing/base/public/gunit.h. _CHECK_MACROS = [ 'DCHECK', 'CHECK', 'EXPECT_TRUE', 'ASSERT_TRUE', 'EXPECT_FALSE', 'ASSERT_FALSE', ] # Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE _CHECK_REPLACEMENT = dict([(macro_var, {}) for macro_var in _CHECK_MACROS]) for op, replacement in [('==', 'EQ'), ('!=', 'NE'), ('>=', 'GE'), ('>', 'GT'), ('<=', 'LE'), ('<', 'LT')]: _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'), ('>=', 'LT'), ('>', 'LE'), ('<=', 'GT'), ('<', 'GE')]: _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement # Alternative tokens and their replacements. For full list, see section 2.5 # Alternative tokens [lex.digraph] in the C++ standard. # # Digraphs (such as '%:') are not included here since it's a mess to # match those on a word boundary. _ALT_TOKEN_REPLACEMENT = { 'and': '&&', 'bitor': '|', 'or': '||', 'xor': '^', 'compl': '~', 'bitand': '&', 'and_eq': '&=', 'or_eq': '|=', 'xor_eq': '^=', 'not': '!', 'not_eq': '!=' } # Compile regular expression that matches all the above keywords. The "[ =()]" # bit is meant to avoid matching these keywords outside of boolean expressions. # # False positives include C-style multi-line comments and multi-line strings # but those have always been troublesome for cpplint. _ALT_TOKEN_REPLACEMENT_PATTERN = re.compile( r'[ =()](' + ('|'.join(_ALT_TOKEN_REPLACEMENT.keys())) + r')(?=[ (]|$)') # These constants define types of headers for use with # _IncludeState.CheckNextIncludeOrder(). _C_SYS_HEADER = 1 _CPP_SYS_HEADER = 2 _OTHER_SYS_HEADER = 3 _LIKELY_MY_HEADER = 4 _POSSIBLE_MY_HEADER = 5 _OTHER_HEADER = 6 # These constants define the current inline assembly state _NO_ASM = 0 # Outside of inline assembly block _INSIDE_ASM = 1 # Inside inline assembly block _END_ASM = 2 # Last line of inline assembly block _BLOCK_ASM = 3 # The whole block is an inline assembly block # Match start of assembly blocks _MATCH_ASM = re.compile(r'^\s*(?:asm|_asm|__asm|__asm__)' r'(?:\s+(volatile|__volatile__))?' r'\s*[{(]') # Match strings that indicate we're working on a C (not C++) file. _SEARCH_C_FILE = re.compile(r'\b(?:LINT_C_FILE|' r'vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))') # Match string that indicates we're working on a Linux Kernel file. _SEARCH_KERNEL_FILE = re.compile(r'\b(?:LINT_KERNEL_FILE)') # Commands for sed to fix the problem _SED_FIXUPS = { 'Remove spaces around =': r's/ = /=/', 'Remove spaces around !=': r's/ != /!=/', 'Remove space before ( in if (': r's/if (/if(/', 'Remove space before ( in for (': r's/for (/for(/', 'Remove space before ( in while (': r's/while (/while(/', 'Remove space before ( in switch (': r's/switch (/switch(/', 'Should have a space between // and comment': r's/\/\//\/\/ /', 'Missing space before {': r's/\([^ ]\){/\1 {/', 'Tab found, replace by spaces': r's/\t/ /g', 'Line ends in whitespace. Consider deleting these extra spaces.': r's/\s*$//', 'You don\'t need a ; after a }': r's/};/}/', 'Missing space after ,': r's/,\([^ ]\)/, \1/g', } _regexp_compile_cache = {} # {str, set(int)}: a map from error categories to sets of linenumbers # on which those errors are expected and should be suppressed. _error_suppressions = {} # The root directory used for deriving header guard CPP variable. # This is set by --root flag. _root = None _root_debug = False # The top level repository directory. If set, _root is calculated relative to # this directory instead of the directory containing version control artifacts. # This is set by the --repository flag. _repository = None # Files to exclude from linting. This is set by the --exclude flag. _excludes = None # Whether to supress all PrintInfo messages, UNRELATED to --quiet flag _quiet = False # The allowed line length of files. # This is set by --linelength flag. _line_length = 80 # This allows to use different include order rule than default _include_order = "default" try: unicode except NameError: # -- pylint: disable=redefined-builtin basestring = unicode = str try: long except NameError: # -- pylint: disable=redefined-builtin long = int if sys.version_info < (3,): # -- pylint: disable=no-member # BINARY_TYPE = str itervalues = dict.itervalues iteritems = dict.iteritems else: # BINARY_TYPE = bytes itervalues = dict.values iteritems = dict.items def unicode_escape_decode(x): if sys.version_info < (3,): return codecs.unicode_escape_decode(x)[0] else: return x # Treat all headers starting with 'h' equally: .h, .hpp, .hxx etc. # This is set by --headers flag. _hpp_headers = set([]) # {str, bool}: a map from error categories to booleans which indicate if the # category should be suppressed for every line. _global_error_suppressions = {} def ProcessHppHeadersOption(val): global _hpp_headers try: _hpp_headers = {ext.strip() for ext in val.split(',')} except ValueError: PrintUsage('Header extensions must be comma separated list.') def ProcessIncludeOrderOption(val): if val is None or val == "default": pass elif val == "standardcfirst": global _include_order _include_order = val else: PrintUsage('Invalid includeorder value %s. Expected default|standardcfirst') def IsHeaderExtension(file_extension): return file_extension in GetHeaderExtensions() def GetHeaderExtensions(): if _hpp_headers: return _hpp_headers if _valid_extensions: return {h for h in _valid_extensions if 'h' in h} return set(['h', 'hh', 'hpp', 'hxx', 'h++', 'cuh']) # The allowed extensions for file names # This is set by --extensions flag def GetAllExtensions(): return GetHeaderExtensions().union(_valid_extensions or set( ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'])) def ProcessExtensionsOption(val): global _valid_extensions try: extensions = [ext.strip() for ext in val.split(',')] _valid_extensions = set(extensions) except ValueError: PrintUsage('Extensions should be a comma-separated list of values;' 'for example: extensions=hpp,cpp\n' 'This could not be parsed: "%s"' % (val,)) def GetNonHeaderExtensions(): return GetAllExtensions().difference(GetHeaderExtensions()) def ParseNolintSuppressions(filename, raw_line, linenum, error): """Updates the global list of line error-suppressions. Parses any NOLINT comments on the current line, updating the global error_suppressions store. Reports an error if the NOLINT comment was malformed. Args: filename: str, the name of the input file. raw_line: str, the line of input text, with comments. linenum: int, the number of the current line. error: function, an error handler. """ matched = Search(r'\bNOLINT(NEXTLINE)?\b(\([^)]+\))?', raw_line) if matched: if matched.group(1): suppressed_line = linenum + 1 else: suppressed_line = linenum category = matched.group(2) if category in (None, '(*)'): # => "suppress all" _error_suppressions.setdefault(None, set()).add(suppressed_line) else: if category.startswith('(') and category.endswith(')'): category = category[1:-1] if category in _ERROR_CATEGORIES: _error_suppressions.setdefault(category, set()).add(suppressed_line) elif category not in _LEGACY_ERROR_CATEGORIES: error(filename, linenum, 'readability/nolint', 5, 'Unknown NOLINT error category: %s' % category) def ProcessGlobalSuppresions(lines): """Updates the list of global error suppressions. Parses any lint directives in the file that have global effect. Args: lines: An array of strings, each representing a line of the file, with the last element being empty if the file is terminated with a newline. """ for line in lines: if _SEARCH_C_FILE.search(line): for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: _global_error_suppressions[category] = True if _SEARCH_KERNEL_FILE.search(line): for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: _global_error_suppressions[category] = True def ResetNolintSuppressions(): """Resets the set of NOLINT suppressions to empty.""" _error_suppressions.clear() _global_error_suppressions.clear() def IsErrorSuppressedByNolint(category, linenum): """Returns true if the specified error category is suppressed on this line. Consults the global error_suppressions map populated by ParseNolintSuppressions/ProcessGlobalSuppresions/ResetNolintSuppressions. Args: category: str, the category of the error. linenum: int, the current line number. Returns: bool, True iff the error should be suppressed due to a NOLINT comment or global suppression. """ return (_global_error_suppressions.get(category, False) or linenum in _error_suppressions.get(category, set()) or linenum in _error_suppressions.get(None, set())) def Match(pattern, s): """Matches the string with the pattern, caching the compiled regexp.""" # The regexp compilation caching is inlined in both Match and Search for # performance reasons; factoring it out into a separate function turns out # to be noticeably expensive. if pattern not in _regexp_compile_cache: _regexp_compile_cache[pattern] = sre_compile.compile(pattern) return _regexp_compile_cache[pattern].match(s) def ReplaceAll(pattern, rep, s): """Replaces instances of pattern in a string with a replacement. The compiled regex is kept in a cache shared by Match and Search. Args: pattern: regex pattern rep: replacement text s: search string Returns: string with replacements made (or original string if no replacements) """ if pattern not in _regexp_compile_cache: _regexp_compile_cache[pattern] = sre_compile.compile(pattern) return _regexp_compile_cache[pattern].sub(rep, s) def Search(pattern, s): """Searches the string for the pattern, caching the compiled regexp.""" if pattern not in _regexp_compile_cache: _regexp_compile_cache[pattern] = sre_compile.compile(pattern) return _regexp_compile_cache[pattern].search(s) def _IsSourceExtension(s): """File extension (excluding dot) matches a source file extension.""" return s in GetNonHeaderExtensions() class _IncludeState(object): """Tracks line numbers for includes, and the order in which includes appear. include_list contains list of lists of (header, line number) pairs. It's a lists of lists rather than just one flat list to make it easier to update across preprocessor boundaries. Call CheckNextIncludeOrder() once for each header in the file, passing in the type constants defined above. Calls in an illegal order will raise an _IncludeError with an appropriate error message. """ # self._section will move monotonically through this set. If it ever # needs to move backwards, CheckNextIncludeOrder will raise an error. _INITIAL_SECTION = 0 _MY_H_SECTION = 1 _C_SECTION = 2 _CPP_SECTION = 3 _OTHER_SYS_SECTION = 4 _OTHER_H_SECTION = 5 _TYPE_NAMES = { _C_SYS_HEADER: 'C system header', _CPP_SYS_HEADER: 'C++ system header', _OTHER_SYS_HEADER: 'other system header', _LIKELY_MY_HEADER: 'header this file implements', _POSSIBLE_MY_HEADER: 'header this file may implement', _OTHER_HEADER: 'other header', } _SECTION_NAMES = { _INITIAL_SECTION: "... nothing. (This can't be an error.)", _MY_H_SECTION: 'a header this file implements', _C_SECTION: 'C system header', _CPP_SECTION: 'C++ system header', _OTHER_SYS_SECTION: 'other system header', _OTHER_H_SECTION: 'other header', } def __init__(self): self.include_list = [[]] self._section = None self._last_header = None self.ResetSection('') def FindHeader(self, header): """Check if a header has already been included. Args: header: header to check. Returns: Line number of previous occurrence, or -1 if the header has not been seen before. """ for section_list in self.include_list: for f in section_list: if f[0] == header: return f[1] return -1 def ResetSection(self, directive): """Reset section checking for preprocessor directive. Args: directive: preprocessor directive (e.g. "if", "else"). """ # The name of the current section. self._section = self._INITIAL_SECTION # The path of last found header. self._last_header = '' # Update list of includes. Note that we never pop from the # include list. if directive in ('if', 'ifdef', 'ifndef'): self.include_list.append([]) elif directive in ('else', 'elif'): self.include_list[-1] = [] def SetLastHeader(self, header_path): self._last_header = header_path def CanonicalizeAlphabeticalOrder(self, header_path): """Returns a path canonicalized for alphabetical comparison. - replaces "-" with "_" so they both cmp the same. - removes '-inl' since we don't require them to be after the main header. - lowercase everything, just in case. Args: header_path: Path to be canonicalized. Returns: Canonicalized path. """ return header_path.replace('-inl.h', '.h').replace('-', '_').lower() def IsInAlphabeticalOrder(self, clean_lines, linenum, header_path): """Check if a header is in alphabetical order with the previous header. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. header_path: Canonicalized header to be checked. Returns: Returns true if the header is in alphabetical order. """ # If previous section is different from current section, _last_header will # be reset to empty string, so it's always less than current header. # # If previous line was a blank line, assume that the headers are # intentionally sorted the way they are. if (self._last_header > header_path and Match(r'^\s*#\s*include\b', clean_lines.elided[linenum - 1])): return False return True def CheckNextIncludeOrder(self, header_type): """Returns a non-empty error message if the next header is out of order. This function also updates the internal state to be ready to check the next include. Args: header_type: One of the _XXX_HEADER constants defined above. Returns: The empty string if the header is in the right order, or an error message describing what's wrong. """ error_message = ('Found %s after %s' % (self._TYPE_NAMES[header_type], self._SECTION_NAMES[self._section])) last_section = self._section if header_type == _C_SYS_HEADER: if self._section <= self._C_SECTION: self._section = self._C_SECTION else: self._last_header = '' return error_message elif header_type == _CPP_SYS_HEADER: if self._section <= self._CPP_SECTION: self._section = self._CPP_SECTION else: self._last_header = '' return error_message elif header_type == _OTHER_SYS_HEADER: if self._section <= self._OTHER_SYS_SECTION: self._section = self._OTHER_SYS_SECTION else: self._last_header = '' return error_message elif header_type == _LIKELY_MY_HEADER: if self._section <= self._MY_H_SECTION: self._section = self._MY_H_SECTION else: self._section = self._OTHER_H_SECTION elif header_type == _POSSIBLE_MY_HEADER: if self._section <= self._MY_H_SECTION: self._section = self._MY_H_SECTION else: # This will always be the fallback because we're not sure # enough that the header is associated with this file. self._section = self._OTHER_H_SECTION else: assert header_type == _OTHER_HEADER self._section = self._OTHER_H_SECTION if last_section != self._section: self._last_header = '' return '' class _CppLintState(object): """Maintains module-wide state..""" def __init__(self): self.verbose_level = 1 # global setting. self.error_count = 0 # global count of reported errors # filters to apply when emitting error messages self.filters = _DEFAULT_FILTERS[:] # backup of filter list. Used to restore the state after each file. self._filters_backup = self.filters[:] self.counting = 'total' # In what way are we counting errors? self.errors_by_category = {} # string to int dict storing error counts self.quiet = False # Suppress non-error messagess? # output format: # "emacs" - format that emacs can parse (default) # "eclipse" - format that eclipse can parse # "vs7" - format that Microsoft Visual Studio 7 can parse # "junit" - format that Jenkins, Bamboo, etc can parse # "sed" - returns a gnu sed command to fix the problem # "gsed" - like sed, but names the command gsed, e.g. for macOS homebrew users self.output_format = 'emacs' # For JUnit output, save errors and failures until the end so that they # can be written into the XML self._junit_errors = [] self._junit_failures = [] def SetOutputFormat(self, output_format): """Sets the output format for errors.""" self.output_format = output_format def SetQuiet(self, quiet): """Sets the module's quiet settings, and returns the previous setting.""" last_quiet = self.quiet self.quiet = quiet return last_quiet def SetVerboseLevel(self, level): """Sets the module's verbosity, and returns the previous setting.""" last_verbose_level = self.verbose_level self.verbose_level = level return last_verbose_level def SetCountingStyle(self, counting_style): """Sets the module's counting options.""" self.counting = counting_style def SetFilters(self, filters): """Sets the error-message filters. These filters are applied when deciding whether to emit a given error message. Args: filters: A string of comma-separated filters (eg "+whitespace/indent"). Each filter should start with + or -; else we die. Raises: ValueError: The comma-separated filters did not all start with '+' or '-'. E.g. "-,+whitespace,-whitespace/indent,whitespace/badfilter" """ # Default filters always have less priority than the flag ones. self.filters = _DEFAULT_FILTERS[:] self.AddFilters(filters) def AddFilters(self, filters): """ Adds more filters to the existing list of error-message filters. """ for filt in filters.split(','): clean_filt = filt.strip() if clean_filt: self.filters.append(clean_filt) for filt in self.filters: if not (filt.startswith('+') or filt.startswith('-')): raise ValueError('Every filter in --filters must start with + or -' ' (%s does not)' % filt) def BackupFilters(self): """ Saves the current filter list to backup storage.""" self._filters_backup = self.filters[:] def RestoreFilters(self): """ Restores filters previously backed up.""" self.filters = self._filters_backup[:] def ResetErrorCounts(self): """Sets the module's error statistic back to zero.""" self.error_count = 0 self.errors_by_category = {} def IncrementErrorCount(self, category): """Bumps the module's error statistic.""" self.error_count += 1 if self.counting in ('toplevel', 'detailed'): if self.counting != 'detailed': category = category.split('/')[0] if category not in self.errors_by_category: self.errors_by_category[category] = 0 self.errors_by_category[category] += 1 def PrintErrorCounts(self): """Print a summary of errors by category, and the total.""" for category, count in sorted(iteritems(self.errors_by_category)): self.PrintInfo('Category \'%s\' errors found: %d\n' % (category, count)) if self.error_count > 0: self.PrintInfo('Total errors found: %d\n' % self.error_count) def PrintInfo(self, message): # _quiet does not represent --quiet flag. # Hide infos from stdout to keep stdout pure for machine consumption if not _quiet and self.output_format not in _MACHINE_OUTPUTS: sys.stdout.write(message) def PrintError(self, message): if self.output_format == 'junit': self._junit_errors.append(message) else: sys.stderr.write(message) def AddJUnitFailure(self, filename, linenum, message, category, confidence): self._junit_failures.append((filename, linenum, message, category, confidence)) def FormatJUnitXML(self): num_errors = len(self._junit_errors) num_failures = len(self._junit_failures) testsuite = xml.etree.ElementTree.Element('testsuite') testsuite.attrib['errors'] = str(num_errors) testsuite.attrib['failures'] = str(num_failures) testsuite.attrib['name'] = 'cpplint' if num_errors == 0 and num_failures == 0: testsuite.attrib['tests'] = str(1) xml.etree.ElementTree.SubElement(testsuite, 'testcase', name='passed') else: testsuite.attrib['tests'] = str(num_errors + num_failures) if num_errors > 0: testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') testcase.attrib['name'] = 'errors' error = xml.etree.ElementTree.SubElement(testcase, 'error') error.text = '\n'.join(self._junit_errors) if num_failures > 0: # Group failures by file failed_file_order = [] failures_by_file = {} for failure in self._junit_failures: failed_file = failure[0] if failed_file not in failed_file_order: failed_file_order.append(failed_file) failures_by_file[failed_file] = [] failures_by_file[failed_file].append(failure) # Create a testcase for each file for failed_file in failed_file_order: failures = failures_by_file[failed_file] testcase = xml.etree.ElementTree.SubElement(testsuite, 'testcase') testcase.attrib['name'] = failed_file failure = xml.etree.ElementTree.SubElement(testcase, 'failure') template = '{0}: {1} [{2}] [{3}]' texts = [template.format(f[1], f[2], f[3], f[4]) for f in failures] failure.text = '\n'.join(texts) xml_decl = '\n' return xml_decl + xml.etree.ElementTree.tostring(testsuite, 'utf-8').decode('utf-8') _cpplint_state = _CppLintState() def _OutputFormat(): """Gets the module's output format.""" return _cpplint_state.output_format def _SetOutputFormat(output_format): """Sets the module's output format.""" _cpplint_state.SetOutputFormat(output_format) def _Quiet(): """Return's the module's quiet setting.""" return _cpplint_state.quiet def _SetQuiet(quiet): """Set the module's quiet status, and return previous setting.""" return _cpplint_state.SetQuiet(quiet) def _VerboseLevel(): """Returns the module's verbosity setting.""" return _cpplint_state.verbose_level def _SetVerboseLevel(level): """Sets the module's verbosity, and returns the previous setting.""" return _cpplint_state.SetVerboseLevel(level) def _SetCountingStyle(level): """Sets the module's counting options.""" _cpplint_state.SetCountingStyle(level) def _Filters(): """Returns the module's list of output filters, as a list.""" return _cpplint_state.filters def _SetFilters(filters): """Sets the module's error-message filters. These filters are applied when deciding whether to emit a given error message. Args: filters: A string of comma-separated filters (eg "whitespace/indent"). Each filter should start with + or -; else we die. """ _cpplint_state.SetFilters(filters) def _AddFilters(filters): """Adds more filter overrides. Unlike _SetFilters, this function does not reset the current list of filters available. Args: filters: A string of comma-separated filters (eg "whitespace/indent"). Each filter should start with + or -; else we die. """ _cpplint_state.AddFilters(filters) def _BackupFilters(): """ Saves the current filter list to backup storage.""" _cpplint_state.BackupFilters() def _RestoreFilters(): """ Restores filters previously backed up.""" _cpplint_state.RestoreFilters() class _FunctionState(object): """Tracks current function name and the number of lines in its body.""" _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc. _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER. def __init__(self): self.in_a_function = False self.lines_in_function = 0 self.current_function = '' def Begin(self, function_name): """Start analyzing function body. Args: function_name: The name of the function being tracked. """ self.in_a_function = True self.lines_in_function = 0 self.current_function = function_name def Count(self): """Count line in current function body.""" if self.in_a_function: self.lines_in_function += 1 def Check(self, error, filename, linenum): """Report if too many lines in function body. Args: error: The function to call with any errors found. filename: The name of the current file. linenum: The number of the line to check. """ if not self.in_a_function: return if Match(r'T(EST|est)', self.current_function): base_trigger = self._TEST_TRIGGER else: base_trigger = self._NORMAL_TRIGGER trigger = base_trigger * 2**_VerboseLevel() if self.lines_in_function > trigger: error_level = int(math.log(self.lines_in_function / base_trigger, 2)) # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ... if error_level > 5: error_level = 5 error(filename, linenum, 'readability/fn_size', error_level, 'Small and focused functions are preferred:' ' %s has %d non-comment lines' ' (error triggered by exceeding %d lines).' % ( self.current_function, self.lines_in_function, trigger)) def End(self): """Stop analyzing function body.""" self.in_a_function = False class _IncludeError(Exception): """Indicates a problem with the include order in a file.""" pass class FileInfo(object): """Provides utility functions for filenames. FileInfo provides easy access to the components of a file's path relative to the project root. """ def __init__(self, filename): self._filename = filename def FullName(self): """Make Windows paths like Unix.""" return os.path.abspath(self._filename).replace('\\', '/') def RepositoryName(self): r"""FullName after removing the local path to the repository. If we have a real absolute path name here we can try to do something smart: detecting the root of the checkout and truncating /path/to/checkout from the name so that we get header guards that don't include things like "C:\\Documents and Settings\\..." or "/home/username/..." in them and thus people on different computers who have checked the source out to different locations won't see bogus errors. """ fullname = self.FullName() if os.path.exists(fullname): project_dir = os.path.dirname(fullname) # If the user specified a repository path, it exists, and the file is # contained in it, use the specified repository path if _repository: repo = FileInfo(_repository).FullName() root_dir = project_dir while os.path.exists(root_dir): # allow case insensitive compare on Windows if os.path.normcase(root_dir) == os.path.normcase(repo): return os.path.relpath(fullname, root_dir).replace('\\', '/') one_up_dir = os.path.dirname(root_dir) if one_up_dir == root_dir: break root_dir = one_up_dir if os.path.exists(os.path.join(project_dir, ".svn")): # If there's a .svn file in the current directory, we recursively look # up the directory tree for the top of the SVN checkout root_dir = project_dir one_up_dir = os.path.dirname(root_dir) while os.path.exists(os.path.join(one_up_dir, ".svn")): root_dir = os.path.dirname(root_dir) one_up_dir = os.path.dirname(one_up_dir) prefix = os.path.commonprefix([root_dir, project_dir]) return fullname[len(prefix) + 1:] # Not SVN <= 1.6? Try to find a git, hg, or svn top level directory by # searching up from the current path. root_dir = current_dir = os.path.dirname(fullname) while current_dir != os.path.dirname(current_dir): if (os.path.exists(os.path.join(current_dir, ".git")) or os.path.exists(os.path.join(current_dir, ".hg")) or os.path.exists(os.path.join(current_dir, ".svn"))): root_dir = current_dir current_dir = os.path.dirname(current_dir) if (os.path.exists(os.path.join(root_dir, ".git")) or os.path.exists(os.path.join(root_dir, ".hg")) or os.path.exists(os.path.join(root_dir, ".svn"))): prefix = os.path.commonprefix([root_dir, project_dir]) return fullname[len(prefix) + 1:] # Don't know what to do; header guard warnings may be wrong... return fullname def Split(self): """Splits the file into the directory, basename, and extension. For 'chrome/browser/browser.cc', Split() would return ('chrome/browser', 'browser', '.cc') Returns: A tuple of (directory, basename, extension). """ googlename = self.RepositoryName() project, rest = os.path.split(googlename) return (project,) + os.path.splitext(rest) def BaseName(self): """File base name - text after the final slash, before the final period.""" return self.Split()[1] def Extension(self): """File extension - text following the final period, includes that period.""" return self.Split()[2] def NoExtension(self): """File has no source file extension.""" return '/'.join(self.Split()[0:2]) def IsSource(self): """File has a source file extension.""" return _IsSourceExtension(self.Extension()[1:]) def _ShouldPrintError(category, confidence, linenum): """If confidence >= verbose, category passes filter and is not suppressed.""" # There are three ways we might decide not to print an error message: # a "NOLINT(category)" comment appears in the source, # the verbosity level isn't high enough, or the filters filter it out. if IsErrorSuppressedByNolint(category, linenum): return False if confidence < _cpplint_state.verbose_level: return False is_filtered = False for one_filter in _Filters(): if one_filter.startswith('-'): if category.startswith(one_filter[1:]): is_filtered = True elif one_filter.startswith('+'): if category.startswith(one_filter[1:]): is_filtered = False else: assert False # should have been checked for in SetFilter. if is_filtered: return False return True def Error(filename, linenum, category, confidence, message): """Logs the fact we've found a lint error. We log where the error was found, and also our confidence in the error, that is, how certain we are this is a legitimate style regression, and not a misidentification or a use that's sometimes justified. False positives can be suppressed by the use of "cpplint(category)" comments on the offending line. These are parsed into _error_suppressions. Args: filename: The name of the file containing the error. linenum: The number of the line containing the error. category: A string used to describe the "category" this bug falls under: "whitespace", say, or "runtime". Categories may have a hierarchy separated by slashes: "whitespace/indent". confidence: A number from 1-5 representing a confidence score for the error, with 5 meaning that we are certain of the problem, and 1 meaning that it could be a legitimate construct. message: The error message. """ if _ShouldPrintError(category, confidence, linenum): _cpplint_state.IncrementErrorCount(category) if _cpplint_state.output_format == 'vs7': _cpplint_state.PrintError('%s(%s): error cpplint: [%s] %s [%d]\n' % ( filename, linenum, category, message, confidence)) elif _cpplint_state.output_format == 'eclipse': sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( filename, linenum, message, category, confidence)) elif _cpplint_state.output_format == 'junit': _cpplint_state.AddJUnitFailure(filename, linenum, message, category, confidence) elif _cpplint_state.output_format in ['sed', 'gsed']: if message in _SED_FIXUPS: sys.stdout.write(_cpplint_state.output_format + " -i '%s%s' %s # %s [%s] [%d]\n" % ( linenum, _SED_FIXUPS[message], filename, message, category, confidence)) else: sys.stderr.write('# %s:%s: "%s" [%s] [%d]\n' % ( filename, linenum, message, category, confidence)) else: final_message = '%s:%s: %s [%s] [%d]\n' % ( filename, linenum, message, category, confidence) sys.stderr.write(final_message) # Matches standard C++ escape sequences per 2.13.2.3 of the C++ standard. _RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile( r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)') # Match a single C style comment on the same line. _RE_PATTERN_C_COMMENTS = r'/\*(?:[^*]|\*(?!/))*\*/' # Matches multi-line C style comments. # This RE is a little bit more complicated than one might expect, because we # have to take care of space removals tools so we can handle comments inside # statements better. # The current rule is: We only clear spaces from both sides when we're at the # end of the line. Otherwise, we try to remove spaces from the right side, # if this doesn't work we try on left side but only if there's a non-character # on the right. _RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile( r'(\s*' + _RE_PATTERN_C_COMMENTS + r'\s*$|' + _RE_PATTERN_C_COMMENTS + r'\s+|' + r'\s+' + _RE_PATTERN_C_COMMENTS + r'(?=\W)|' + _RE_PATTERN_C_COMMENTS + r')') def IsCppString(line): """Does line terminate so, that the next symbol is in string constant. This function does not consider single-line nor multi-line comments. Args: line: is a partial line of code starting from the 0..n. Returns: True, if next character appended to 'line' is inside a string constant. """ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \" return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1 def CleanseRawStrings(raw_lines): """Removes C++11 raw strings from lines. Before: static const char kData[] = R"( multi-line string )"; After: static const char kData[] = "" (replaced by blank line) ""; Args: raw_lines: list of raw lines. Returns: list of lines with C++11 raw strings replaced by empty strings. """ delimiter = None lines_without_raw_strings = [] for line in raw_lines: if delimiter: # Inside a raw string, look for the end end = line.find(delimiter) if end >= 0: # Found the end of the string, match leading space for this # line and resume copying the original lines, and also insert # a "" on the last line. leading_space = Match(r'^(\s*)\S', line) line = leading_space.group(1) + '""' + line[end + len(delimiter):] delimiter = None else: # Haven't found the end yet, append a blank line. line = '""' # Look for beginning of a raw string, and replace them with # empty strings. This is done in a loop to handle multiple raw # strings on the same line. while delimiter is None: # Look for beginning of a raw string. # See 2.14.15 [lex.string] for syntax. # # Once we have matched a raw string, we check the prefix of the # line to make sure that the line is not part of a single line # comment. It's done this way because we remove raw strings # before removing comments as opposed to removing comments # before removing raw strings. This is because there are some # cpplint checks that requires the comments to be preserved, but # we don't want to check comments that are inside raw strings. matched = Match(r'^(.*?)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) if (matched and not Match(r'^([^\'"]|\'(\\.|[^\'])*\'|"(\\.|[^"])*")*//', matched.group(1))): delimiter = ')' + matched.group(2) + '"' end = matched.group(3).find(delimiter) if end >= 0: # Raw string ended on same line line = (matched.group(1) + '""' + matched.group(3)[end + len(delimiter):]) delimiter = None else: # Start of a multi-line raw string line = matched.group(1) + '""' else: break lines_without_raw_strings.append(line) # TODO(unknown): if delimiter is not None here, we might want to # emit a warning for unterminated string. return lines_without_raw_strings def FindNextMultiLineCommentStart(lines, lineix): """Find the beginning marker for a multiline comment.""" while lineix < len(lines): if lines[lineix].strip().startswith('/*'): # Only return this marker if the comment goes beyond this line if lines[lineix].strip().find('*/', 2) < 0: return lineix lineix += 1 return len(lines) def FindNextMultiLineCommentEnd(lines, lineix): """We are inside a comment, find the end marker.""" while lineix < len(lines): if lines[lineix].strip().endswith('*/'): return lineix lineix += 1 return len(lines) def RemoveMultiLineCommentsFromRange(lines, begin, end): """Clears a range of lines for multi-line comments.""" # Having // comments makes the lines non-empty, so we will not get # unnecessary blank line warnings later in the code. for i in range(begin, end): lines[i] = '/**/' def RemoveMultiLineComments(filename, lines, error): """Removes multiline (c-style) comments from lines.""" lineix = 0 while lineix < len(lines): lineix_begin = FindNextMultiLineCommentStart(lines, lineix) if lineix_begin >= len(lines): return lineix_end = FindNextMultiLineCommentEnd(lines, lineix_begin) if lineix_end >= len(lines): error(filename, lineix_begin + 1, 'readability/multiline_comment', 5, 'Could not find end of multi-line comment') return RemoveMultiLineCommentsFromRange(lines, lineix_begin, lineix_end + 1) lineix = lineix_end + 1 def CleanseComments(line): """Removes //-comments and single-line C-style /* */ comments. Args: line: A line of C++ source. Returns: The line with single-line comments removed. """ commentpos = line.find('//') if commentpos != -1 and not IsCppString(line[:commentpos]): line = line[:commentpos].rstrip() # get rid of /* ... */ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line) class CleansedLines(object): """Holds 4 copies of all lines with different preprocessing applied to them. 1) elided member contains lines without strings and comments. 2) lines member contains lines without comments. 3) raw_lines member contains all the lines without processing. 4) lines_without_raw_strings member is same as raw_lines, but with C++11 raw strings removed. All these members are of , and of the same length. """ def __init__(self, lines): self.elided = [] self.lines = [] self.raw_lines = lines self.num_lines = len(lines) self.lines_without_raw_strings = CleanseRawStrings(lines) for linenum in range(len(self.lines_without_raw_strings)): self.lines.append(CleanseComments( self.lines_without_raw_strings[linenum])) elided = self._CollapseStrings(self.lines_without_raw_strings[linenum]) self.elided.append(CleanseComments(elided)) def NumLines(self): """Returns the number of lines represented.""" return self.num_lines @staticmethod def _CollapseStrings(elided): """Collapses strings and chars on a line to simple "" or '' blocks. We nix strings first so we're not fooled by text like '"http://"' Args: elided: The line being processed. Returns: The line with collapsed strings. """ if _RE_PATTERN_INCLUDE.match(elided): return elided # Remove escaped characters first to make quote/single quote collapsing # basic. Things that look like escaped characters shouldn't occur # outside of strings and chars. elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided) # Replace quoted strings and digit separators. Both single quotes # and double quotes are processed in the same loop, otherwise # nested quotes wouldn't work. collapsed = '' while True: # Find the first quote character match = Match(r'^([^\'"]*)([\'"])(.*)$', elided) if not match: collapsed += elided break head, quote, tail = match.groups() if quote == '"': # Collapse double quoted strings second_quote = tail.find('"') if second_quote >= 0: collapsed += head + '""' elided = tail[second_quote + 1:] else: # Unmatched double quote, don't bother processing the rest # of the line since this is probably a multiline string. collapsed += elided break else: # Found single quote, check nearby text to eliminate digit separators. # # There is no special handling for floating point here, because # the integer/fractional/exponent parts would all be parsed # correctly as long as there are digits on both sides of the # separator. So we are fine as long as we don't see something # like "0.'3" (gcc 4.9.0 will not allow this literal). if Search(r'\b(?:0[bBxX]?|[1-9])[0-9a-fA-F]*$', head): match_literal = Match(r'^((?:\'?[0-9a-zA-Z_])*)(.*)$', "'" + tail) collapsed += head + match_literal.group(1).replace("'", '') elided = match_literal.group(2) else: second_quote = tail.find('\'') if second_quote >= 0: collapsed += head + "''" elided = tail[second_quote + 1:] else: # Unmatched single quote collapsed += elided break return collapsed def FindEndOfExpressionInLine(line, startpos, stack): """Find the position just after the end of current parenthesized expression. Args: line: a CleansedLines line. startpos: start searching at this position. stack: nesting stack at startpos. Returns: On finding matching end: (index just after matching end, None) On finding an unclosed expression: (-1, None) Otherwise: (-1, new stack at end of this line) """ for i in xrange(startpos, len(line)): char = line[i] if char in '([{': # Found start of parenthesized expression, push to expression stack stack.append(char) elif char == '<': # Found potential start of template argument list if i > 0 and line[i - 1] == '<': # Left shift operator if stack and stack[-1] == '<': stack.pop() if not stack: return (-1, None) elif i > 0 and Search(r'\boperator\s*$', line[0:i]): # operator<, don't add to stack continue else: # Tentative start of template argument list stack.append('<') elif char in ')]}': # Found end of parenthesized expression. # # If we are currently expecting a matching '>', the pending '<' # must have been an operator. Remove them from expression stack. while stack and stack[-1] == '<': stack.pop() if not stack: return (-1, None) if ((stack[-1] == '(' and char == ')') or (stack[-1] == '[' and char == ']') or (stack[-1] == '{' and char == '}')): stack.pop() if not stack: return (i + 1, None) else: # Mismatched parentheses return (-1, None) elif char == '>': # Found potential end of template argument list. # Ignore "->" and operator functions if (i > 0 and (line[i - 1] == '-' or Search(r'\boperator\s*$', line[0:i - 1]))): continue # Pop the stack if there is a matching '<'. Otherwise, ignore # this '>' since it must be an operator. if stack: if stack[-1] == '<': stack.pop() if not stack: return (i + 1, None) elif char == ';': # Found something that look like end of statements. If we are currently # expecting a '>', the matching '<' must have been an operator, since # template argument list should not contain statements. while stack and stack[-1] == '<': stack.pop() if not stack: return (-1, None) # Did not find end of expression or unbalanced parentheses on this line return (-1, stack) def CloseExpression(clean_lines, linenum, pos): """If input points to ( or { or [ or <, finds the position that closes it. If lines[linenum][pos] points to a '(' or '{' or '[' or '<', finds the linenum/pos that correspond to the closing of the expression. TODO(unknown): cpplint spends a fair bit of time matching parentheses. Ideally we would want to index all opening and closing parentheses once and have CloseExpression be just a simple lookup, but due to preprocessor tricks, this is not so easy. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. pos: A position on the line. Returns: A tuple (line, linenum, pos) pointer *past* the closing brace, or (line, len(lines), -1) if we never find a close. Note we ignore strings and comments when matching; and the line we return is the 'cleansed' line at linenum. """ line = clean_lines.elided[linenum] if (line[pos] not in '({[<') or Match(r'<[<=]', line[pos:]): return (line, clean_lines.NumLines(), -1) # Check first line (end_pos, stack) = FindEndOfExpressionInLine(line, pos, []) if end_pos > -1: return (line, linenum, end_pos) # Continue scanning forward while stack and linenum < clean_lines.NumLines() - 1: linenum += 1 line = clean_lines.elided[linenum] (end_pos, stack) = FindEndOfExpressionInLine(line, 0, stack) if end_pos > -1: return (line, linenum, end_pos) # Did not find end of expression before end of file, give up return (line, clean_lines.NumLines(), -1) def FindStartOfExpressionInLine(line, endpos, stack): """Find position at the matching start of current expression. This is almost the reverse of FindEndOfExpressionInLine, but note that the input position and returned position differs by 1. Args: line: a CleansedLines line. endpos: start searching at this position. stack: nesting stack at endpos. Returns: On finding matching start: (index at matching start, None) On finding an unclosed expression: (-1, None) Otherwise: (-1, new stack at beginning of this line) """ i = endpos while i >= 0: char = line[i] if char in ')]}': # Found end of expression, push to expression stack stack.append(char) elif char == '>': # Found potential end of template argument list. # # Ignore it if it's a "->" or ">=" or "operator>" if (i > 0 and (line[i - 1] == '-' or Match(r'\s>=\s', line[i - 1:]) or Search(r'\boperator\s*$', line[0:i]))): i -= 1 else: stack.append('>') elif char == '<': # Found potential start of template argument list if i > 0 and line[i - 1] == '<': # Left shift operator i -= 1 else: # If there is a matching '>', we can pop the expression stack. # Otherwise, ignore this '<' since it must be an operator. if stack and stack[-1] == '>': stack.pop() if not stack: return (i, None) elif char in '([{': # Found start of expression. # # If there are any unmatched '>' on the stack, they must be # operators. Remove those. while stack and stack[-1] == '>': stack.pop() if not stack: return (-1, None) if ((char == '(' and stack[-1] == ')') or (char == '[' and stack[-1] == ']') or (char == '{' and stack[-1] == '}')): stack.pop() if not stack: return (i, None) else: # Mismatched parentheses return (-1, None) elif char == ';': # Found something that look like end of statements. If we are currently # expecting a '<', the matching '>' must have been an operator, since # template argument list should not contain statements. while stack and stack[-1] == '>': stack.pop() if not stack: return (-1, None) i -= 1 return (-1, stack) def ReverseCloseExpression(clean_lines, linenum, pos): """If input points to ) or } or ] or >, finds the position that opens it. If lines[linenum][pos] points to a ')' or '}' or ']' or '>', finds the linenum/pos that correspond to the opening of the expression. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. pos: A position on the line. Returns: A tuple (line, linenum, pos) pointer *at* the opening brace, or (line, 0, -1) if we never find the matching opening brace. Note we ignore strings and comments when matching; and the line we return is the 'cleansed' line at linenum. """ line = clean_lines.elided[linenum] if line[pos] not in ')}]>': return (line, 0, -1) # Check last line (start_pos, stack) = FindStartOfExpressionInLine(line, pos, []) if start_pos > -1: return (line, linenum, start_pos) # Continue scanning backward while stack and linenum > 0: linenum -= 1 line = clean_lines.elided[linenum] (start_pos, stack) = FindStartOfExpressionInLine(line, len(line) - 1, stack) if start_pos > -1: return (line, linenum, start_pos) # Did not find start of expression before beginning of file, give up return (line, 0, -1) def CheckForCopyright(filename, lines, error): """Logs an error if no Copyright message appears at the top of the file.""" # We'll say it should occur by line 10. Don't forget there's a # placeholder line at the front. for line in xrange(1, min(len(lines), 11)): if re.search(r'Copyright', lines[line], re.I): break else: # means no copyright line was found error(filename, 0, 'legal/copyright', 5, 'No copyright message found. ' 'You should have a line: "Copyright [year] "') def GetIndentLevel(line): """Return the number of leading spaces in line. Args: line: A string to check. Returns: An integer count of leading spaces, possibly zero. """ indent = Match(r'^( *)\S', line) if indent: return len(indent.group(1)) else: return 0 def PathSplitToList(path): """Returns the path split into a list by the separator. Args: path: An absolute or relative path (e.g. '/a/b/c/' or '../a') Returns: A list of path components (e.g. ['a', 'b', 'c]). """ lst = [] while True: (head, tail) = os.path.split(path) if head == path: # absolute paths end lst.append(head) break if tail == path: # relative paths end lst.append(tail) break path = head lst.append(tail) lst.reverse() return lst def GetHeaderGuardCPPVariable(filename): """Returns the CPP variable that should be used as a header guard. Args: filename: The name of a C++ header file. Returns: The CPP variable that should be used as a header guard in the named file. """ # Restores original filename in case that cpplint is invoked from Emacs's # flymake. filename = re.sub(r'_flymake\.h$', '.h', filename) filename = re.sub(r'/\.flymake/([^/]*)$', r'/\1', filename) # Replace 'c++' with 'cpp'. filename = filename.replace('C++', 'cpp').replace('c++', 'cpp') fileinfo = FileInfo(filename) file_path_from_root = fileinfo.RepositoryName() def FixupPathFromRoot(): if _root_debug: sys.stderr.write("\n_root fixup, _root = '%s', repository name = '%s'\n" % (_root, fileinfo.RepositoryName())) # Process the file path with the --root flag if it was set. if not _root: if _root_debug: sys.stderr.write("_root unspecified\n") return file_path_from_root def StripListPrefix(lst, prefix): # f(['x', 'y'], ['w, z']) -> None (not a valid prefix) if lst[:len(prefix)] != prefix: return None # f(['a, 'b', 'c', 'd'], ['a', 'b']) -> ['c', 'd'] return lst[(len(prefix)):] # root behavior: # --root=subdir , lstrips subdir from the header guard maybe_path = StripListPrefix(PathSplitToList(file_path_from_root), PathSplitToList(_root)) if _root_debug: sys.stderr.write(("_root lstrip (maybe_path=%s, file_path_from_root=%s," + " _root=%s)\n") % (maybe_path, file_path_from_root, _root)) if maybe_path: return os.path.join(*maybe_path) # --root=.. , will prepend the outer directory to the header guard full_path = fileinfo.FullName() # adapt slashes for windows root_abspath = os.path.abspath(_root).replace('\\', '/') maybe_path = StripListPrefix(PathSplitToList(full_path), PathSplitToList(root_abspath)) if _root_debug: sys.stderr.write(("_root prepend (maybe_path=%s, full_path=%s, " + "root_abspath=%s)\n") % (maybe_path, full_path, root_abspath)) if maybe_path: return os.path.join(*maybe_path) if _root_debug: sys.stderr.write("_root ignore, returning %s\n" % (file_path_from_root)) # --root=FAKE_DIR is ignored return file_path_from_root file_path_from_root = FixupPathFromRoot() return re.sub(r'[^a-zA-Z0-9]', '_', file_path_from_root).upper() + '_' def CheckForHeaderGuard(filename, clean_lines, error): """Checks that the file contains a header guard. Logs an error if no #ifndef header guard is present. For other headers, checks that the full pathname is used. Args: filename: The name of the C++ header file. clean_lines: A CleansedLines instance containing the file. error: The function to call with any errors found. """ # Don't check for header guards if there are error suppression # comments somewhere in this file. # # Because this is silencing a warning for a nonexistent line, we # only support the very specific NOLINT(build/header_guard) syntax, # and not the general NOLINT or NOLINT(*) syntax. raw_lines = clean_lines.lines_without_raw_strings for i in raw_lines: if Search(r'//\s*NOLINT\(build/header_guard\)', i): return # Allow pragma once instead of header guards for i in raw_lines: if Search(r'^\s*#pragma\s+once', i): return cppvar = GetHeaderGuardCPPVariable(filename) ifndef = '' ifndef_linenum = 0 define = '' endif = '' endif_linenum = 0 for linenum, line in enumerate(raw_lines): linesplit = line.split() if len(linesplit) >= 2: # find the first occurrence of #ifndef and #define, save arg if not ifndef and linesplit[0] == '#ifndef': # set ifndef to the header guard presented on the #ifndef line. ifndef = linesplit[1] ifndef_linenum = linenum if not define and linesplit[0] == '#define': define = linesplit[1] # find the last occurrence of #endif, save entire line if line.startswith('#endif'): endif = line endif_linenum = linenum if not ifndef or not define or ifndef != define: error(filename, 0, 'build/header_guard', 5, 'No #ifndef header guard found, suggested CPP variable is: %s' % cppvar) return # The guard should be PATH_FILE_H_, but we also allow PATH_FILE_H__ # for backward compatibility. if ifndef != cppvar: error_level = 0 if ifndef != cppvar + '_': error_level = 5 ParseNolintSuppressions(filename, raw_lines[ifndef_linenum], ifndef_linenum, error) error(filename, ifndef_linenum, 'build/header_guard', error_level, '#ifndef header guard has wrong style, please use: %s' % cppvar) # Check for "//" comments on endif line. ParseNolintSuppressions(filename, raw_lines[endif_linenum], endif_linenum, error) match = Match(r'#endif\s*//\s*' + cppvar + r'(_)?\b', endif) if match: if match.group(1) == '_': # Issue low severity warning for deprecated double trailing underscore error(filename, endif_linenum, 'build/header_guard', 0, '#endif line should be "#endif // %s"' % cppvar) return # Didn't find the corresponding "//" comment. If this file does not # contain any "//" comments at all, it could be that the compiler # only wants "/**/" comments, look for those instead. no_single_line_comments = True for i in xrange(1, len(raw_lines) - 1): line = raw_lines[i] if Match(r'^(?:(?:\'(?:\.|[^\'])*\')|(?:"(?:\.|[^"])*")|[^\'"])*//', line): no_single_line_comments = False break if no_single_line_comments: match = Match(r'#endif\s*/\*\s*' + cppvar + r'(_)?\s*\*/', endif) if match: if match.group(1) == '_': # Low severity warning for double trailing underscore error(filename, endif_linenum, 'build/header_guard', 0, '#endif line should be "#endif /* %s */"' % cppvar) return # Didn't find anything error(filename, endif_linenum, 'build/header_guard', 5, '#endif line should be "#endif // %s"' % cppvar) def CheckHeaderFileIncluded(filename, include_state, error): """Logs an error if a source file does not include its header.""" # Do not check test files fileinfo = FileInfo(filename) if Search(_TEST_FILE_SUFFIX, fileinfo.BaseName()): return for ext in GetHeaderExtensions(): basefilename = filename[0:len(filename) - len(fileinfo.Extension())] headerfile = basefilename + '.' + ext if not os.path.exists(headerfile): continue headername = FileInfo(headerfile).RepositoryName() first_include = None include_uses_unix_dir_aliases = False for section_list in include_state.include_list: for f in section_list: include_text = f[0] if "./" in include_text: include_uses_unix_dir_aliases = True if headername in include_text or include_text in headername: return if not first_include: first_include = f[1] message = '%s should include its header file %s' % (fileinfo.RepositoryName(), headername) if include_uses_unix_dir_aliases: message += ". Relative paths like . and .. are not allowed." error(filename, first_include, 'build/include', 5, message) def CheckForBadCharacters(filename, lines, error): """Logs an error for each line containing bad characters. Two kinds of bad characters: 1. Unicode replacement characters: These indicate that either the file contained invalid UTF-8 (likely) or Unicode replacement characters (which it shouldn't). Note that it's possible for this to throw off line numbering if the invalid UTF-8 occurred adjacent to a newline. 2. NUL bytes. These are problematic for some tools. Args: filename: The name of the current file. lines: An array of strings, each representing a line of the file. error: The function to call with any errors found. """ for linenum, line in enumerate(lines): if unicode_escape_decode('\ufffd') in line: error(filename, linenum, 'readability/utf8', 5, 'Line contains invalid UTF-8 (or Unicode replacement character).') if '\0' in line: error(filename, linenum, 'readability/nul', 5, 'Line contains NUL byte.') def CheckForNewlineAtEOF(filename, lines, error): """Logs an error if there is no newline char at the end of the file. Args: filename: The name of the current file. lines: An array of strings, each representing a line of the file. error: The function to call with any errors found. """ # The array lines() was created by adding two newlines to the # original file (go figure), then splitting on \n. # To verify that the file ends in \n, we just have to make sure the # last-but-two element of lines() exists and is empty. if len(lines) < 3 or lines[-2]: error(filename, len(lines) - 2, 'whitespace/ending_newline', 5, 'Could not find a newline character at the end of the file.') def CheckForMultilineCommentsAndStrings(filename, clean_lines, linenum, error): """Logs an error if we see /* ... */ or "..." that extend past one line. /* ... */ comments are legit inside macros, for one line. Otherwise, we prefer // comments, so it's ok to warn about the other. Likewise, it's ok for strings to extend across multiple lines, as long as a line continuation character (backslash) terminates each line. Although not currently prohibited by the C++ style guide, it's ugly and unnecessary. We don't do well with either in this lint program, so we warn about both. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Remove all \\ (escaped backslashes) from the line. They are OK, and the # second (escaped) slash may trigger later \" detection erroneously. line = line.replace('\\\\', '') if line.count('/*') > line.count('*/'): error(filename, linenum, 'readability/multiline_comment', 5, 'Complex multi-line /*...*/-style comment found. ' 'Lint may give bogus warnings. ' 'Consider replacing these with //-style comments, ' 'with #if 0...#endif, ' 'or with more clearly structured multi-line comments.') if (line.count('"') - line.count('\\"')) % 2: error(filename, linenum, 'readability/multiline_string', 5, 'Multi-line string ("...") found. This lint script doesn\'t ' 'do well with such strings, and may give bogus warnings. ' 'Use C++11 raw strings or concatenation instead.') # (non-threadsafe name, thread-safe alternative, validation pattern) # # The validation pattern is used to eliminate false positives such as: # _rand(); // false positive due to substring match. # ->rand(); // some member function rand(). # ACMRandom rand(seed); // some variable named rand. # ISAACRandom rand(); // another variable named rand. # # Basically we require the return value of these functions to be used # in some expression context on the same line by matching on some # operator before the function name. This eliminates constructors and # member function calls. _UNSAFE_FUNC_PREFIX = r'(?:[-+*/=%^&|(<]\s*|>\s+)' _THREADING_LIST = ( ('asctime(', 'asctime_r(', _UNSAFE_FUNC_PREFIX + r'asctime\([^)]+\)'), ('ctime(', 'ctime_r(', _UNSAFE_FUNC_PREFIX + r'ctime\([^)]+\)'), ('getgrgid(', 'getgrgid_r(', _UNSAFE_FUNC_PREFIX + r'getgrgid\([^)]+\)'), ('getgrnam(', 'getgrnam_r(', _UNSAFE_FUNC_PREFIX + r'getgrnam\([^)]+\)'), ('getlogin(', 'getlogin_r(', _UNSAFE_FUNC_PREFIX + r'getlogin\(\)'), ('getpwnam(', 'getpwnam_r(', _UNSAFE_FUNC_PREFIX + r'getpwnam\([^)]+\)'), ('getpwuid(', 'getpwuid_r(', _UNSAFE_FUNC_PREFIX + r'getpwuid\([^)]+\)'), ('gmtime(', 'gmtime_r(', _UNSAFE_FUNC_PREFIX + r'gmtime\([^)]+\)'), ('localtime(', 'localtime_r(', _UNSAFE_FUNC_PREFIX + r'localtime\([^)]+\)'), ('rand(', 'rand_r(', _UNSAFE_FUNC_PREFIX + r'rand\(\)'), ('strtok(', 'strtok_r(', _UNSAFE_FUNC_PREFIX + r'strtok\([^)]+\)'), ('ttyname(', 'ttyname_r(', _UNSAFE_FUNC_PREFIX + r'ttyname\([^)]+\)'), ) def CheckPosixThreading(filename, clean_lines, linenum, error): """Checks for calls to thread-unsafe functions. Much code has been originally written without consideration of multi-threading. Also, engineers are relying on their old experience; they have learned posix before threading extensions were added. These tests guide the engineers to use thread-safe functions (when using posix directly). Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] for single_thread_func, multithread_safe_func, pattern in _THREADING_LIST: # Additional pattern matching check to confirm that this is the # function we are looking for if Search(pattern, line): error(filename, linenum, 'runtime/threadsafe_fn', 2, 'Consider using ' + multithread_safe_func + '...) instead of ' + single_thread_func + '...) for improved thread safety.') def CheckVlogArguments(filename, clean_lines, linenum, error): """Checks that VLOG() is only used for defining a logging level. For example, VLOG(2) is correct. VLOG(INFO), VLOG(WARNING), VLOG(ERROR), and VLOG(FATAL) are not. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] if Search(r'\bVLOG\((INFO|ERROR|WARNING|DFATAL|FATAL)\)', line): error(filename, linenum, 'runtime/vlog', 5, 'VLOG() should be used with numeric verbosity level. ' 'Use LOG() if you want symbolic severity levels.') # Matches invalid increment: *count++, which moves pointer instead of # incrementing a value. _RE_PATTERN_INVALID_INCREMENT = re.compile( r'^\s*\*\w+(\+\+|--);') def CheckInvalidIncrement(filename, clean_lines, linenum, error): """Checks for invalid increment *count++. For example following function: void increment_counter(int* count) { *count++; } is invalid, because it effectively does count++, moving pointer, and should be replaced with ++*count, (*count)++ or *count += 1. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] if _RE_PATTERN_INVALID_INCREMENT.match(line): error(filename, linenum, 'runtime/invalid_increment', 5, 'Changing pointer instead of value (or unused value of operator*).') def IsMacroDefinition(clean_lines, linenum): if Search(r'^#define', clean_lines[linenum]): return True if linenum > 0 and Search(r'\\$', clean_lines[linenum - 1]): return True return False def IsForwardClassDeclaration(clean_lines, linenum): return Match(r'^\s*(\btemplate\b)*.*class\s+\w+;\s*$', clean_lines[linenum]) class _BlockInfo(object): """Stores information about a generic block of code.""" def __init__(self, linenum, seen_open_brace): self.starting_linenum = linenum self.seen_open_brace = seen_open_brace self.open_parentheses = 0 self.inline_asm = _NO_ASM self.check_namespace_indentation = False def CheckBegin(self, filename, clean_lines, linenum, error): """Run checks that applies to text up to the opening brace. This is mostly for checking the text after the class identifier and the "{", usually where the base class is specified. For other blocks, there isn't much to check, so we always pass. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ pass def CheckEnd(self, filename, clean_lines, linenum, error): """Run checks that applies to text after the closing brace. This is mostly used for checking end of namespace comments. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ pass def IsBlockInfo(self): """Returns true if this block is a _BlockInfo. This is convenient for verifying that an object is an instance of a _BlockInfo, but not an instance of any of the derived classes. Returns: True for this class, False for derived classes. """ return self.__class__ == _BlockInfo class _ExternCInfo(_BlockInfo): """Stores information about an 'extern "C"' block.""" def __init__(self, linenum): _BlockInfo.__init__(self, linenum, True) class _ClassInfo(_BlockInfo): """Stores information about a class.""" def __init__(self, name, class_or_struct, clean_lines, linenum): _BlockInfo.__init__(self, linenum, False) self.name = name self.is_derived = False self.check_namespace_indentation = True if class_or_struct == 'struct': self.access = 'public' self.is_struct = True else: self.access = 'private' self.is_struct = False # Remember initial indentation level for this class. Using raw_lines here # instead of elided to account for leading comments. self.class_indent = GetIndentLevel(clean_lines.raw_lines[linenum]) # Try to find the end of the class. This will be confused by things like: # class A { # } *x = { ... # # But it's still good enough for CheckSectionSpacing. self.last_line = 0 depth = 0 for i in range(linenum, clean_lines.NumLines()): line = clean_lines.elided[i] depth += line.count('{') - line.count('}') if not depth: self.last_line = i break def CheckBegin(self, filename, clean_lines, linenum, error): # Look for a bare ':' if Search('(^|[^:]):($|[^:])', clean_lines.elided[linenum]): self.is_derived = True def CheckEnd(self, filename, clean_lines, linenum, error): # If there is a DISALLOW macro, it should appear near the end of # the class. seen_last_thing_in_class = False for i in xrange(linenum - 1, self.starting_linenum, -1): match = Search( r'\b(DISALLOW_COPY_AND_ASSIGN|DISALLOW_IMPLICIT_CONSTRUCTORS)\(' + self.name + r'\)', clean_lines.elided[i]) if match: if seen_last_thing_in_class: error(filename, i, 'readability/constructors', 3, match.group(1) + ' should be the last thing in the class') break if not Match(r'^\s*$', clean_lines.elided[i]): seen_last_thing_in_class = True # Check that closing brace is aligned with beginning of the class. # Only do this if the closing brace is indented by only whitespaces. # This means we will not check single-line class definitions. indent = Match(r'^( *)\}', clean_lines.elided[linenum]) if indent and len(indent.group(1)) != self.class_indent: if self.is_struct: parent = 'struct ' + self.name else: parent = 'class ' + self.name error(filename, linenum, 'whitespace/indent', 3, 'Closing brace should be aligned with beginning of %s' % parent) class _NamespaceInfo(_BlockInfo): """Stores information about a namespace.""" def __init__(self, name, linenum): _BlockInfo.__init__(self, linenum, False) self.name = name or '' self.check_namespace_indentation = True def CheckEnd(self, filename, clean_lines, linenum, error): """Check end of namespace comments.""" line = clean_lines.raw_lines[linenum] # Check how many lines is enclosed in this namespace. Don't issue # warning for missing namespace comments if there aren't enough # lines. However, do apply checks if there is already an end of # namespace comment and it's incorrect. # # TODO(unknown): We always want to check end of namespace comments # if a namespace is large, but sometimes we also want to apply the # check if a short namespace contained nontrivial things (something # other than forward declarations). There is currently no logic on # deciding what these nontrivial things are, so this check is # triggered by namespace size only, which works most of the time. if (linenum - self.starting_linenum < 10 and not Match(r'^\s*};*\s*(//|/\*).*\bnamespace\b', line)): return # Look for matching comment at end of namespace. # # Note that we accept C style "/* */" comments for terminating # namespaces, so that code that terminate namespaces inside # preprocessor macros can be cpplint clean. # # We also accept stuff like "// end of namespace ." with the # period at the end. # # Besides these, we don't accept anything else, otherwise we might # get false negatives when existing comment is a substring of the # expected namespace. if self.name: # Named namespace if not Match((r'^\s*};*\s*(//|/\*).*\bnamespace\s+' + re.escape(self.name) + r'[\*/\.\\\s]*$'), line): error(filename, linenum, 'readability/namespace', 5, 'Namespace should be terminated with "// namespace %s"' % self.name) else: # Anonymous namespace if not Match(r'^\s*};*\s*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): # If "// namespace anonymous" or "// anonymous namespace (more text)", # mention "// anonymous namespace" as an acceptable form if Match(r'^\s*}.*\b(namespace anonymous|anonymous namespace)\b', line): error(filename, linenum, 'readability/namespace', 5, 'Anonymous namespace should be terminated with "// namespace"' ' or "// anonymous namespace"') else: error(filename, linenum, 'readability/namespace', 5, 'Anonymous namespace should be terminated with "// namespace"') class _PreprocessorInfo(object): """Stores checkpoints of nesting stacks when #if/#else is seen.""" def __init__(self, stack_before_if): # The entire nesting stack before #if self.stack_before_if = stack_before_if # The entire nesting stack up to #else self.stack_before_else = [] # Whether we have already seen #else or #elif self.seen_else = False class NestingState(object): """Holds states related to parsing braces.""" def __init__(self): # Stack for tracking all braces. An object is pushed whenever we # see a "{", and popped when we see a "}". Only 3 types of # objects are possible: # - _ClassInfo: a class or struct. # - _NamespaceInfo: a namespace. # - _BlockInfo: some other type of block. self.stack = [] # Top of the previous stack before each Update(). # # Because the nesting_stack is updated at the end of each line, we # had to do some convoluted checks to find out what is the current # scope at the beginning of the line. This check is simplified by # saving the previous top of nesting stack. # # We could save the full stack, but we only need the top. Copying # the full nesting stack would slow down cpplint by ~10%. self.previous_stack_top = [] # Stack of _PreprocessorInfo objects. self.pp_stack = [] def SeenOpenBrace(self): """Check if we have seen the opening brace for the innermost block. Returns: True if we have seen the opening brace, False if the innermost block is still expecting an opening brace. """ return (not self.stack) or self.stack[-1].seen_open_brace def InNamespaceBody(self): """Check if we are currently one level inside a namespace body. Returns: True if top of the stack is a namespace block, False otherwise. """ return self.stack and isinstance(self.stack[-1], _NamespaceInfo) def InExternC(self): """Check if we are currently one level inside an 'extern "C"' block. Returns: True if top of the stack is an extern block, False otherwise. """ return self.stack and isinstance(self.stack[-1], _ExternCInfo) def InClassDeclaration(self): """Check if we are currently one level inside a class or struct declaration. Returns: True if top of the stack is a class/struct, False otherwise. """ return self.stack and isinstance(self.stack[-1], _ClassInfo) def InAsmBlock(self): """Check if we are currently one level inside an inline ASM block. Returns: True if the top of the stack is a block containing inline ASM. """ return self.stack and self.stack[-1].inline_asm != _NO_ASM def InTemplateArgumentList(self, clean_lines, linenum, pos): """Check if current position is inside template argument list. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. pos: position just after the suspected template argument. Returns: True if (linenum, pos) is inside template arguments. """ while linenum < clean_lines.NumLines(): # Find the earliest character that might indicate a template argument line = clean_lines.elided[linenum] match = Match(r'^[^{};=\[\]\.<>]*(.)', line[pos:]) if not match: linenum += 1 pos = 0 continue token = match.group(1) pos += len(match.group(0)) # These things do not look like template argument list: # class Suspect { # class Suspect x; } if token in ('{', '}', ';'): return False # These things look like template argument list: # template # template # template # template if token in ('>', '=', '[', ']', '.'): return True # Check if token is an unmatched '<'. # If not, move on to the next character. if token != '<': pos += 1 if pos >= len(line): linenum += 1 pos = 0 continue # We can't be sure if we just find a single '<', and need to # find the matching '>'. (_, end_line, end_pos) = CloseExpression(clean_lines, linenum, pos - 1) if end_pos < 0: # Not sure if template argument list or syntax error in file return False linenum = end_line pos = end_pos return False def UpdatePreprocessor(self, line): """Update preprocessor stack. We need to handle preprocessors due to classes like this: #ifdef SWIG struct ResultDetailsPageElementExtensionPoint { #else struct ResultDetailsPageElementExtensionPoint : public Extension { #endif We make the following assumptions (good enough for most files): - Preprocessor condition evaluates to true from #if up to first #else/#elif/#endif. - Preprocessor condition evaluates to false from #else/#elif up to #endif. We still perform lint checks on these lines, but these do not affect nesting stack. Args: line: current line to check. """ if Match(r'^\s*#\s*(if|ifdef|ifndef)\b', line): # Beginning of #if block, save the nesting stack here. The saved # stack will allow us to restore the parsing state in the #else case. self.pp_stack.append(_PreprocessorInfo(copy.deepcopy(self.stack))) elif Match(r'^\s*#\s*(else|elif)\b', line): # Beginning of #else block if self.pp_stack: if not self.pp_stack[-1].seen_else: # This is the first #else or #elif block. Remember the # whole nesting stack up to this point. This is what we # keep after the #endif. self.pp_stack[-1].seen_else = True self.pp_stack[-1].stack_before_else = copy.deepcopy(self.stack) # Restore the stack to how it was before the #if self.stack = copy.deepcopy(self.pp_stack[-1].stack_before_if) else: # TODO(unknown): unexpected #else, issue warning? pass elif Match(r'^\s*#\s*endif\b', line): # End of #if or #else blocks. if self.pp_stack: # If we saw an #else, we will need to restore the nesting # stack to its former state before the #else, otherwise we # will just continue from where we left off. if self.pp_stack[-1].seen_else: # Here we can just use a shallow copy since we are the last # reference to it. self.stack = self.pp_stack[-1].stack_before_else # Drop the corresponding #if self.pp_stack.pop() else: # TODO(unknown): unexpected #endif, issue warning? pass # TODO(unknown): Update() is too long, but we will refactor later. def Update(self, filename, clean_lines, linenum, error): """Update nesting state with current line. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Remember top of the previous nesting stack. # # The stack is always pushed/popped and not modified in place, so # we can just do a shallow copy instead of copy.deepcopy. Using # deepcopy would slow down cpplint by ~28%. if self.stack: self.previous_stack_top = self.stack[-1] else: self.previous_stack_top = None # Update pp_stack self.UpdatePreprocessor(line) # Count parentheses. This is to avoid adding struct arguments to # the nesting stack. if self.stack: inner_block = self.stack[-1] depth_change = line.count('(') - line.count(')') inner_block.open_parentheses += depth_change # Also check if we are starting or ending an inline assembly block. if inner_block.inline_asm in (_NO_ASM, _END_ASM): if (depth_change != 0 and inner_block.open_parentheses == 1 and _MATCH_ASM.match(line)): # Enter assembly block inner_block.inline_asm = _INSIDE_ASM else: # Not entering assembly block. If previous line was _END_ASM, # we will now shift to _NO_ASM state. inner_block.inline_asm = _NO_ASM elif (inner_block.inline_asm == _INSIDE_ASM and inner_block.open_parentheses == 0): # Exit assembly block inner_block.inline_asm = _END_ASM # Consume namespace declaration at the beginning of the line. Do # this in a loop so that we catch same line declarations like this: # namespace proto2 { namespace bridge { class MessageSet; } } while True: # Match start of namespace. The "\b\s*" below catches namespace # declarations even if it weren't followed by a whitespace, this # is so that we don't confuse our namespace checker. The # missing spaces will be flagged by CheckSpacing. namespace_decl_match = Match(r'^\s*namespace\b\s*([:\w]+)?(.*)$', line) if not namespace_decl_match: break new_namespace = _NamespaceInfo(namespace_decl_match.group(1), linenum) self.stack.append(new_namespace) line = namespace_decl_match.group(2) if line.find('{') != -1: new_namespace.seen_open_brace = True line = line[line.find('{') + 1:] # Look for a class declaration in whatever is left of the line # after parsing namespaces. The regexp accounts for decorated classes # such as in: # class LOCKABLE API Object { # }; class_decl_match = Match( r'^(\s*(?:template\s*<[\w\s<>,:=]*>\s*)?' r'(class|struct)\s+(?:[a-zA-Z0-9_]+\s+)*(\w+(?:::\w+)*))' r'(.*)$', line) if (class_decl_match and (not self.stack or self.stack[-1].open_parentheses == 0)): # We do not want to accept classes that are actually template arguments: # template , # template class Ignore3> # void Function() {}; # # To avoid template argument cases, we scan forward and look for # an unmatched '>'. If we see one, assume we are inside a # template argument list. end_declaration = len(class_decl_match.group(1)) if not self.InTemplateArgumentList(clean_lines, linenum, end_declaration): self.stack.append(_ClassInfo( class_decl_match.group(3), class_decl_match.group(2), clean_lines, linenum)) line = class_decl_match.group(4) # If we have not yet seen the opening brace for the innermost block, # run checks here. if not self.SeenOpenBrace(): self.stack[-1].CheckBegin(filename, clean_lines, linenum, error) # Update access control if we are inside a class/struct if self.stack and isinstance(self.stack[-1], _ClassInfo): classinfo = self.stack[-1] access_match = Match( r'^(.*)\b(public|private|protected|signals)(\s+(?:slots\s*)?)?' r':(?:[^:]|$)', line) if access_match: classinfo.access = access_match.group(2) # Check that access keywords are indented +1 space. Skip this # check if the keywords are not preceded by whitespaces. indent = access_match.group(1) if (len(indent) != classinfo.class_indent + 1 and Match(r'^\s*$', indent)): if classinfo.is_struct: parent = 'struct ' + classinfo.name else: parent = 'class ' + classinfo.name slots = '' if access_match.group(3): slots = access_match.group(3) error(filename, linenum, 'whitespace/indent', 3, '%s%s: should be indented +1 space inside %s' % ( access_match.group(2), slots, parent)) # Consume braces or semicolons from what's left of the line while True: # Match first brace, semicolon, or closed parenthesis. matched = Match(r'^[^{;)}]*([{;)}])(.*)$', line) if not matched: break token = matched.group(1) if token == '{': # If namespace or class hasn't seen a opening brace yet, mark # namespace/class head as complete. Push a new block onto the # stack otherwise. if not self.SeenOpenBrace(): self.stack[-1].seen_open_brace = True elif Match(r'^extern\s*"[^"]*"\s*\{', line): self.stack.append(_ExternCInfo(linenum)) else: self.stack.append(_BlockInfo(linenum, True)) if _MATCH_ASM.match(line): self.stack[-1].inline_asm = _BLOCK_ASM elif token == ';' or token == ')': # If we haven't seen an opening brace yet, but we already saw # a semicolon, this is probably a forward declaration. Pop # the stack for these. # # Similarly, if we haven't seen an opening brace yet, but we # already saw a closing parenthesis, then these are probably # function arguments with extra "class" or "struct" keywords. # Also pop these stack for these. if not self.SeenOpenBrace(): self.stack.pop() else: # token == '}' # Perform end of block checks and pop the stack. if self.stack: self.stack[-1].CheckEnd(filename, clean_lines, linenum, error) self.stack.pop() line = matched.group(2) def InnermostClass(self): """Get class info on the top of the stack. Returns: A _ClassInfo object if we are inside a class, or None otherwise. """ for i in range(len(self.stack), 0, -1): classinfo = self.stack[i - 1] if isinstance(classinfo, _ClassInfo): return classinfo return None def CheckCompletedBlocks(self, filename, error): """Checks that all classes and namespaces have been completely parsed. Call this when all lines in a file have been processed. Args: filename: The name of the current file. error: The function to call with any errors found. """ # Note: This test can result in false positives if #ifdef constructs # get in the way of brace matching. See the testBuildClass test in # cpplint_unittest.py for an example of this. for obj in self.stack: if isinstance(obj, _ClassInfo): error(filename, obj.starting_linenum, 'build/class', 5, 'Failed to find complete declaration of class %s' % obj.name) elif isinstance(obj, _NamespaceInfo): error(filename, obj.starting_linenum, 'build/namespaces', 5, 'Failed to find complete declaration of namespace %s' % obj.name) def CheckForNonStandardConstructs(filename, clean_lines, linenum, nesting_state, error): r"""Logs an error if we see certain non-ANSI constructs ignored by gcc-2. Complain about several constructs which gcc-2 accepts, but which are not standard C++. Warning about these in lint is one way to ease the transition to new compilers. - put storage class first (e.g. "static const" instead of "const static"). - "%lld" instead of %qd" in printf-type functions. - "%1$d" is non-standard in printf-type functions. - "\%" is an undefined character escape sequence. - text after #endif is not allowed. - invalid inner-style forward declaration. - >? and ?= and )\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line): error(filename, linenum, 'build/deprecated', 3, '>? and ))?' # r'\s*const\s*' + type_name + '\s*&\s*\w+\s*;' error(filename, linenum, 'runtime/member_string_references', 2, 'const string& members are dangerous. It is much better to use ' 'alternatives, such as pointers or simple constants.') # Everything else in this function operates on class declarations. # Return early if the top of the nesting stack is not a class, or if # the class head is not completed yet. classinfo = nesting_state.InnermostClass() if not classinfo or not classinfo.seen_open_brace: return # The class may have been declared with namespace or classname qualifiers. # The constructor and destructor will not have those qualifiers. base_classname = classinfo.name.split('::')[-1] # Look for single-argument constructors that aren't marked explicit. # Technically a valid construct, but against style. explicit_constructor_match = Match( r'\s+(?:(?:inline|constexpr)\s+)*(explicit\s+)?' r'(?:(?:inline|constexpr)\s+)*%s\s*' r'\(((?:[^()]|\([^()]*\))*)\)' % re.escape(base_classname), line) if explicit_constructor_match: is_marked_explicit = explicit_constructor_match.group(1) if not explicit_constructor_match.group(2): constructor_args = [] else: constructor_args = explicit_constructor_match.group(2).split(',') # collapse arguments so that commas in template parameter lists and function # argument parameter lists don't split arguments in two i = 0 while i < len(constructor_args): constructor_arg = constructor_args[i] while (constructor_arg.count('<') > constructor_arg.count('>') or constructor_arg.count('(') > constructor_arg.count(')')): constructor_arg += ',' + constructor_args[i + 1] del constructor_args[i + 1] constructor_args[i] = constructor_arg i += 1 variadic_args = [arg for arg in constructor_args if '&&...' in arg] defaulted_args = [arg for arg in constructor_args if '=' in arg] noarg_constructor = (not constructor_args or # empty arg list # 'void' arg specifier (len(constructor_args) == 1 and constructor_args[0].strip() == 'void')) onearg_constructor = ((len(constructor_args) == 1 and # exactly one arg not noarg_constructor) or # all but at most one arg defaulted (len(constructor_args) >= 1 and not noarg_constructor and len(defaulted_args) >= len(constructor_args) - 1) or # variadic arguments with zero or one argument (len(constructor_args) <= 2 and len(variadic_args) >= 1)) initializer_list_constructor = bool( onearg_constructor and Search(r'\bstd\s*::\s*initializer_list\b', constructor_args[0])) copy_constructor = bool( onearg_constructor and Match(r'((const\s+(volatile\s+)?)?|(volatile\s+(const\s+)?))?' r'%s(\s*<[^>]*>)?(\s+const)?\s*(?:<\w+>\s*)?&' % re.escape(base_classname), constructor_args[0].strip())) if (not is_marked_explicit and onearg_constructor and not initializer_list_constructor and not copy_constructor): if defaulted_args or variadic_args: error(filename, linenum, 'runtime/explicit', 5, 'Constructors callable with one argument ' 'should be marked explicit.') else: error(filename, linenum, 'runtime/explicit', 5, 'Single-parameter constructors should be marked explicit.') elif is_marked_explicit and not onearg_constructor: if noarg_constructor: error(filename, linenum, 'runtime/explicit', 5, 'Zero-parameter constructors should not be marked explicit.') def CheckSpacingForFunctionCall(filename, clean_lines, linenum, error): """Checks for the correctness of various spacing around function calls. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Since function calls often occur inside if/for/while/switch # expressions - which have their own, more liberal conventions - we # first see if we should be looking inside such an expression for a # function call, to which we can apply more strict standards. fncall = line # if there's no control flow construct, look at whole line for pattern in (r'\bif\s*\((.*)\)\s*{', r'\bfor\s*\((.*)\)\s*{', r'\bwhile\s*\((.*)\)\s*[{;]', r'\bswitch\s*\((.*)\)\s*{'): match = Search(pattern, line) if match: fncall = match.group(1) # look inside the parens for function calls break # Except in if/for/while/switch, there should never be space # immediately inside parens (eg "f( 3, 4 )"). We make an exception # for nested parens ( (a+b) + c ). Likewise, there should never be # a space before a ( when it's a function argument. I assume it's a # function argument when the char before the whitespace is legal in # a function name (alnum + _) and we're not starting a macro. Also ignore # pointers and references to arrays and functions coz they're too tricky: # we use a very simple way to recognize these: # " (something)(maybe-something)" or # " (something)(maybe-something," or # " (something)[something]" # Note that we assume the contents of [] to be short enough that # they'll never need to wrap. if ( # Ignore control structures. not Search(r'\b(if|for|while|switch|return|new|delete|catch|sizeof)\b', fncall) and # Ignore pointers/references to functions. not Search(r' \([^)]+\)\([^)]*(\)|,$)', fncall) and # Ignore pointers/references to arrays. not Search(r' \([^)]+\)\[[^\]]+\]', fncall)): if Search(r'\w\s*\(\s(?!\s*\\$)', fncall): # a ( used for a fn call error(filename, linenum, 'whitespace/parens', 4, 'Extra space after ( in function call') elif Search(r'\(\s+(?!(\s*\\)|\()', fncall): error(filename, linenum, 'whitespace/parens', 2, 'Extra space after (') if (Search(r'\w\s+\(', fncall) and not Search(r'_{0,2}asm_{0,2}\s+_{0,2}volatile_{0,2}\s+\(', fncall) and not Search(r'#\s*define|typedef|using\s+\w+\s*=', fncall) and not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall) and not Search(r'\bcase\s+\(', fncall)): # TODO(unknown): Space after an operator function seem to be a common # error, silence those for now by restricting them to highest verbosity. if Search(r'\boperator_*\b', line): error(filename, linenum, 'whitespace/parens', 0, 'Extra space before ( in function call') else: error(filename, linenum, 'whitespace/parens', 4, 'Extra space before ( in function call') # If the ) is followed only by a newline or a { + newline, assume it's # part of a control statement (if/while/etc), and don't complain if Search(r'[^)]\s+\)\s*[^{\s]', fncall): # If the closing parenthesis is preceded by only whitespaces, # try to give a more descriptive error message. if Search(r'^\s+\)', fncall): error(filename, linenum, 'whitespace/parens', 2, 'Closing ) should be moved to the previous line') else: error(filename, linenum, 'whitespace/parens', 2, 'Extra space before )') def IsBlankLine(line): """Returns true if the given line is blank. We consider a line to be blank if the line is empty or consists of only white spaces. Args: line: A line of a string. Returns: True, if the given line is blank. """ return not line or line.isspace() def CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, error): is_namespace_indent_item = ( len(nesting_state.stack) > 1 and nesting_state.stack[-1].check_namespace_indentation and isinstance(nesting_state.previous_stack_top, _NamespaceInfo) and nesting_state.previous_stack_top == nesting_state.stack[-2]) if ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, clean_lines.elided, line): CheckItemIndentationInNamespace(filename, clean_lines.elided, line, error) def CheckForFunctionLengths(filename, clean_lines, linenum, function_state, error): """Reports for long function bodies. For an overview why this is done, see: https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions Uses a simplistic algorithm assuming other style guidelines (especially spacing) are followed. Only checks unindented functions, so class members are unchecked. Trivial bodies are unchecked, so constructors with huge initializer lists may be missed. Blank/comment lines are not counted so as to avoid encouraging the removal of vertical space and comments just to get through a lint check. NOLINT *on the last line of a function* disables this check. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. function_state: Current function name and lines in body so far. error: The function to call with any errors found. """ lines = clean_lines.lines line = lines[linenum] joined_line = '' starting_func = False regexp = r'(\w(\w|::|\*|\&|\s)*)\(' # decls * & space::name( ... match_result = Match(regexp, line) if match_result: # If the name is all caps and underscores, figure it's a macro and # ignore it, unless it's TEST or TEST_F. function_name = match_result.group(1).split()[-1] if function_name == 'TEST' or function_name == 'TEST_F' or ( not Match(r'[A-Z_]+$', function_name)): starting_func = True if starting_func: body_found = False for start_linenum in xrange(linenum, clean_lines.NumLines()): start_line = lines[start_linenum] joined_line += ' ' + start_line.lstrip() if Search(r'(;|})', start_line): # Declarations and trivial functions body_found = True break # ... ignore if Search(r'{', start_line): body_found = True function = Search(r'((\w|:)*)\(', line).group(1) if Match(r'TEST', function): # Handle TEST... macros parameter_regexp = Search(r'(\(.*\))', joined_line) if parameter_regexp: # Ignore bad syntax function += parameter_regexp.group(1) else: function += '()' function_state.Begin(function) break if not body_found: # No body for the function (or evidence of a non-function) was found. error(filename, linenum, 'readability/fn_size', 5, 'Lint failed to find start of function body.') elif Match(r'^\}\s*$', line): # function end function_state.Check(error, filename, linenum) function_state.End() elif not Match(r'^\s*$', line): function_state.Count() # Count non-blank/non-comment lines. _RE_PATTERN_TODO = re.compile(r'^//(\s*)TODO(\(.+?\))?:?(\s|$)?') def CheckComment(line, filename, linenum, next_line_start, error): """Checks for common mistakes in comments. Args: line: The line in question. filename: The name of the current file. linenum: The number of the line to check. next_line_start: The first non-whitespace column of the next line. error: The function to call with any errors found. """ commentpos = line.find('//') if commentpos != -1: # Check if the // may be in quotes. If so, ignore it if re.sub(r'\\.', '', line[0:commentpos]).count('"') % 2 == 0: # Allow one space for new scopes, two spaces otherwise: if (not (Match(r'^.*{ *//', line) and next_line_start == commentpos) and ((commentpos >= 1 and line[commentpos-1] not in string.whitespace) or (commentpos >= 2 and line[commentpos-2] not in string.whitespace))): error(filename, linenum, 'whitespace/comments', 2, 'At least two spaces is best between code and comments') # Checks for common mistakes in TODO comments. comment = line[commentpos:] match = _RE_PATTERN_TODO.match(comment) if match: # One whitespace is correct; zero whitespace is handled elsewhere. leading_whitespace = match.group(1) if len(leading_whitespace) > 1: error(filename, linenum, 'whitespace/todo', 2, 'Too many spaces before TODO') username = match.group(2) if not username: error(filename, linenum, 'readability/todo', 2, 'Missing username in TODO; it should look like ' '"// TODO(my_username): Stuff."') middle_whitespace = match.group(3) # Comparisons made explicit for correctness -- pylint: disable=g-explicit-bool-comparison if middle_whitespace != ' ' and middle_whitespace != '': error(filename, linenum, 'whitespace/todo', 2, 'TODO(my_username) should be followed by a space') # If the comment contains an alphanumeric character, there # should be a space somewhere between it and the // unless # it's a /// or //! Doxygen comment. if (Match(r'//[^ ]*\w', comment) and not Match(r'(///|//\!)(\s+|$)', comment)): error(filename, linenum, 'whitespace/comments', 4, 'Should have a space between // and comment') def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): """Checks for the correctness of various spacing issues in the code. Things we check for: spaces around operators, spaces after if/for/while/switch, no spaces around parens in function calls, two spaces between code and comment, don't start a block with a blank line, don't end a function with a blank line, don't add a blank line after public/protected/private, don't have too many blank lines in a row. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: The function to call with any errors found. """ # Don't use "elided" lines here, otherwise we can't check commented lines. # Don't want to use "raw" either, because we don't want to check inside C++11 # raw strings, raw = clean_lines.lines_without_raw_strings line = raw[linenum] # Before nixing comments, check if the line is blank for no good # reason. This includes the first line after a block is opened, and # blank lines at the end of a function (ie, right before a line like '}' # # Skip all the blank line checks if we are immediately inside a # namespace body. In other words, don't issue blank line warnings # for this block: # namespace { # # } # # A warning about missing end of namespace comments will be issued instead. # # Also skip blank line checks for 'extern "C"' blocks, which are formatted # like namespaces. if (IsBlankLine(line) and not nesting_state.InNamespaceBody() and not nesting_state.InExternC()): elided = clean_lines.elided prev_line = elided[linenum - 1] prevbrace = prev_line.rfind('{') # TODO(unknown): Don't complain if line before blank line, and line after, # both start with alnums and are indented the same amount. # This ignores whitespace at the start of a namespace block # because those are not usually indented. if prevbrace != -1 and prev_line[prevbrace:].find('}') == -1: # OK, we have a blank line at the start of a code block. Before we # complain, we check if it is an exception to the rule: The previous # non-empty line has the parameters of a function header that are indented # 4 spaces (because they did not fit in a 80 column line when placed on # the same line as the function name). We also check for the case where # the previous line is indented 6 spaces, which may happen when the # initializers of a constructor do not fit into a 80 column line. exception = False if Match(r' {6}\w', prev_line): # Initializer list? # We are looking for the opening column of initializer list, which # should be indented 4 spaces to cause 6 space indentation afterwards. search_position = linenum-2 while (search_position >= 0 and Match(r' {6}\w', elided[search_position])): search_position -= 1 exception = (search_position >= 0 and elided[search_position][:5] == ' :') else: # Search for the function arguments or an initializer list. We use a # simple heuristic here: If the line is indented 4 spaces; and we have a # closing paren, without the opening paren, followed by an opening brace # or colon (for initializer lists) we assume that it is the last line of # a function header. If we have a colon indented 4 spaces, it is an # initializer list. exception = (Match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)', prev_line) or Match(r' {4}:', prev_line)) if not exception: error(filename, linenum, 'whitespace/blank_line', 2, 'Redundant blank line at the start of a code block ' 'should be deleted.') # Ignore blank lines at the end of a block in a long if-else # chain, like this: # if (condition1) { # // Something followed by a blank line # # } else if (condition2) { # // Something else # } if linenum + 1 < clean_lines.NumLines(): next_line = raw[linenum + 1] if (next_line and Match(r'\s*}', next_line) and next_line.find('} else ') == -1): error(filename, linenum, 'whitespace/blank_line', 3, 'Redundant blank line at the end of a code block ' 'should be deleted.') matched = Match(r'\s*(public|protected|private):', prev_line) if matched: error(filename, linenum, 'whitespace/blank_line', 3, 'Do not leave a blank line after "%s:"' % matched.group(1)) # Next, check comments next_line_start = 0 if linenum + 1 < clean_lines.NumLines(): next_line = raw[linenum + 1] next_line_start = len(next_line) - len(next_line.lstrip()) CheckComment(line, filename, linenum, next_line_start, error) # get rid of comments and strings line = clean_lines.elided[linenum] # You shouldn't have spaces before your brackets, except for C++11 attributes # or maybe after 'delete []', 'return []() {};', or 'auto [abc, ...] = ...;'. if (Search(r'\w\s+\[(?!\[)', line) and not Search(r'(?:auto&?|delete|return)\s+\[', line)): error(filename, linenum, 'whitespace/braces', 5, 'Extra space before [') # In range-based for, we wanted spaces before and after the colon, but # not around "::" tokens that might appear. if (Search(r'for *\(.*[^:]:[^: ]', line) or Search(r'for *\(.*[^: ]:[^:]', line)): error(filename, linenum, 'whitespace/forcolon', 2, 'Missing space around colon in range-based for loop') def CheckOperatorSpacing(filename, clean_lines, linenum, error): """Checks for horizontal spacing around operators. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Don't try to do spacing checks for operator methods. Do this by # replacing the troublesome characters with something else, # preserving column position for all other characters. # # The replacement is done repeatedly to avoid false positives from # operators that call operators. while True: match = Match(r'^(.*\boperator\b)(\S+)(\s*\(.*)$', line) if match: line = match.group(1) + ('_' * len(match.group(2))) + match.group(3) else: break # We allow no-spaces around = within an if: "if ( (a=Foo()) == 0 )". # Otherwise not. Note we only check for non-spaces on *both* sides; # sometimes people put non-spaces on one side when aligning ='s among # many lines (not that this is behavior that I approve of...) if ((Search(r'[\w.]=', line) or Search(r'=[\w.]', line)) and not Search(r'\b(if|while|for) ', line) # Operators taken from [lex.operators] in C++11 standard. and not Search(r'(>=|<=|==|!=|&=|\^=|\|=|\+=|\*=|\/=|\%=)', line) and not Search(r'operator=', line)): error(filename, linenum, 'whitespace/operators', 4, 'Missing spaces around =') # It's ok not to have spaces around binary operators like + - * /, but if # there's too little whitespace, we get concerned. It's hard to tell, # though, so we punt on this one for now. TODO. # You should always have whitespace around binary operators. # # Check <= and >= first to avoid false positives with < and >, then # check non-include lines for spacing around < and >. # # If the operator is followed by a comma, assume it's be used in a # macro context and don't do any checks. This avoids false # positives. # # Note that && is not included here. This is because there are too # many false positives due to RValue references. match = Search(r'[^<>=!\s](==|!=|<=|>=|\|\|)[^<>=!\s,;\)]', line) if match: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around %s' % match.group(1)) elif not Match(r'#.*include', line): # Look for < that is not surrounded by spaces. This is only # triggered if both sides are missing spaces, even though # technically should should flag if at least one side is missing a # space. This is done to avoid some false positives with shifts. match = Match(r'^(.*[^\s<])<[^\s=<,]', line) if match: (_, _, end_pos) = CloseExpression( clean_lines, linenum, len(match.group(1))) if end_pos <= -1: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around <') # Look for > that is not surrounded by spaces. Similar to the # above, we only trigger if both sides are missing spaces to avoid # false positives with shifts. match = Match(r'^(.*[^-\s>])>[^\s=>,]', line) if match: (_, _, start_pos) = ReverseCloseExpression( clean_lines, linenum, len(match.group(1))) if start_pos <= -1: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around >') # We allow no-spaces around << when used like this: 10<<20, but # not otherwise (particularly, not when used as streams) # # We also allow operators following an opening parenthesis, since # those tend to be macros that deal with operators. match = Search(r'(operator|[^\s(<])(?:L|UL|LL|ULL|l|ul|ll|ull)?<<([^\s,=<])', line) if (match and not (match.group(1).isdigit() and match.group(2).isdigit()) and not (match.group(1) == 'operator' and match.group(2) == ';')): error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around <<') # We allow no-spaces around >> for almost anything. This is because # C++11 allows ">>" to close nested templates, which accounts for # most cases when ">>" is not followed by a space. # # We still warn on ">>" followed by alpha character, because that is # likely due to ">>" being used for right shifts, e.g.: # value >> alpha # # When ">>" is used to close templates, the alphanumeric letter that # follows would be part of an identifier, and there should still be # a space separating the template type and the identifier. # type> alpha match = Search(r'>>[a-zA-Z_]', line) if match: error(filename, linenum, 'whitespace/operators', 3, 'Missing spaces around >>') # There shouldn't be space around unary operators match = Search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line) if match: error(filename, linenum, 'whitespace/operators', 4, 'Extra space for operator %s' % match.group(1)) def CheckParenthesisSpacing(filename, clean_lines, linenum, error): """Checks for horizontal spacing around parentheses. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # No spaces after an if, while, switch, or for match = Search(r' (if\(|for\(|while\(|switch\()', line) if match: error(filename, linenum, 'whitespace/parens', 5, 'Missing space before ( in %s' % match.group(1)) # For if/for/while/switch, the left and right parens should be # consistent about how many spaces are inside the parens, and # there should either be zero or one spaces inside the parens. # We don't want: "if ( foo)" or "if ( foo )". # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed. match = Search(r'\b(if|for|while|switch)\s*' r'\(([ ]*)(.).*[^ ]+([ ]*)\)\s*{\s*$', line) if match: if len(match.group(2)) != len(match.group(4)): if not (match.group(3) == ';' and len(match.group(2)) == 1 + len(match.group(4)) or not match.group(2) and Search(r'\bfor\s*\(.*; \)', line)): error(filename, linenum, 'whitespace/parens', 5, 'Mismatching spaces inside () in %s' % match.group(1)) if len(match.group(2)) not in [0, 1]: error(filename, linenum, 'whitespace/parens', 5, 'Should have zero or one spaces inside ( and ) in %s' % match.group(1)) def CheckCommaSpacing(filename, clean_lines, linenum, error): """Checks for horizontal spacing near commas and semicolons. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ raw = clean_lines.lines_without_raw_strings line = clean_lines.elided[linenum] # You should always have a space after a comma (either as fn arg or operator) # # This does not apply when the non-space character following the # comma is another comma, since the only time when that happens is # for empty macro arguments. # # We run this check in two passes: first pass on elided lines to # verify that lines contain missing whitespaces, second pass on raw # lines to confirm that those missing whitespaces are not due to # elided comments. if (Search(r',[^,\s]', ReplaceAll(r'\boperator\s*,\s*\(', 'F(', line)) and Search(r',[^,\s]', raw[linenum])): error(filename, linenum, 'whitespace/comma', 3, 'Missing space after ,') # You should always have a space after a semicolon # except for few corner cases # TODO(unknown): clarify if 'if (1) { return 1;}' is requires one more # space after ; if Search(r';[^\s};\\)/]', line): error(filename, linenum, 'whitespace/semicolon', 3, 'Missing space after ;') def _IsType(clean_lines, nesting_state, expr): """Check if expression looks like a type name, returns true if so. Args: clean_lines: A CleansedLines instance containing the file. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. expr: The expression to check. Returns: True, if token looks like a type. """ # Keep only the last token in the expression last_word = Match(r'^.*(\b\S+)$', expr) if last_word: token = last_word.group(1) else: token = expr # Match native types and stdint types if _TYPES.match(token): return True # Try a bit harder to match templated types. Walk up the nesting # stack until we find something that resembles a typename # declaration for what we are looking for. typename_pattern = (r'\b(?:typename|class|struct)\s+' + re.escape(token) + r'\b') block_index = len(nesting_state.stack) - 1 while block_index >= 0: if isinstance(nesting_state.stack[block_index], _NamespaceInfo): return False # Found where the opening brace is. We want to scan from this # line up to the beginning of the function, minus a few lines. # template # class C # : public ... { // start scanning here last_line = nesting_state.stack[block_index].starting_linenum next_block_start = 0 if block_index > 0: next_block_start = nesting_state.stack[block_index - 1].starting_linenum first_line = last_line while first_line >= next_block_start: if clean_lines.elided[first_line].find('template') >= 0: break first_line -= 1 if first_line < next_block_start: # Didn't find any "template" keyword before reaching the next block, # there are probably no template things to check for this block block_index -= 1 continue # Look for typename in the specified range for i in xrange(first_line, last_line + 1, 1): if Search(typename_pattern, clean_lines.elided[i]): return True block_index -= 1 return False def CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error): """Checks for horizontal spacing near commas. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Except after an opening paren, or after another opening brace (in case of # an initializer list, for instance), you should have spaces before your # braces when they are delimiting blocks, classes, namespaces etc. # And since you should never have braces at the beginning of a line, # this is an easy test. Except that braces used for initialization don't # follow the same rule; we often don't want spaces before those. match = Match(r'^(.*[^ ({>]){', line) if match: # Try a bit harder to check for brace initialization. This # happens in one of the following forms: # Constructor() : initializer_list_{} { ... } # Constructor{}.MemberFunction() # Type variable{}; # FunctionCall(type{}, ...); # LastArgument(..., type{}); # LOG(INFO) << type{} << " ..."; # map_of_type[{...}] = ...; # ternary = expr ? new type{} : nullptr; # OuterTemplate{}> # # We check for the character following the closing brace, and # silence the warning if it's one of those listed above, i.e. # "{.;,)<>]:". # # To account for nested initializer list, we allow any number of # closing braces up to "{;,)<". We can't simply silence the # warning on first sight of closing brace, because that would # cause false negatives for things that are not initializer lists. # Silence this: But not this: # Outer{ if (...) { # Inner{...} if (...){ // Missing space before { # }; } # # There is a false negative with this approach if people inserted # spurious semicolons, e.g. "if (cond){};", but we will catch the # spurious semicolon with a separate check. leading_text = match.group(1) (endline, endlinenum, endpos) = CloseExpression( clean_lines, linenum, len(match.group(1))) trailing_text = '' if endpos > -1: trailing_text = endline[endpos:] for offset in xrange(endlinenum + 1, min(endlinenum + 3, clean_lines.NumLines() - 1)): trailing_text += clean_lines.elided[offset] # We also suppress warnings for `uint64_t{expression}` etc., as the style # guide recommends brace initialization for integral types to avoid # overflow/truncation. if (not Match(r'^[\s}]*[{.;,)<>\]:]', trailing_text) and not _IsType(clean_lines, nesting_state, leading_text)): error(filename, linenum, 'whitespace/braces', 5, 'Missing space before {') # Make sure '} else {' has spaces. if Search(r'}else', line): error(filename, linenum, 'whitespace/braces', 5, 'Missing space before else') # You shouldn't have a space before a semicolon at the end of the line. # There's a special case for "for" since the style guide allows space before # the semicolon there. if Search(r':\s*;\s*$', line): error(filename, linenum, 'whitespace/semicolon', 5, 'Semicolon defining empty statement. Use {} instead.') elif Search(r'^\s*;\s*$', line): error(filename, linenum, 'whitespace/semicolon', 5, 'Line contains only semicolon. If this should be an empty statement, ' 'use {} instead.') elif (Search(r'\s+;\s*$', line) and not Search(r'\bfor\b', line)): error(filename, linenum, 'whitespace/semicolon', 5, 'Extra space before last semicolon. If this should be an empty ' 'statement, use {} instead.') def IsDecltype(clean_lines, linenum, column): """Check if the token ending on (linenum, column) is decltype(). Args: clean_lines: A CleansedLines instance containing the file. linenum: the number of the line to check. column: end column of the token to check. Returns: True if this token is decltype() expression, False otherwise. """ (text, _, start_col) = ReverseCloseExpression(clean_lines, linenum, column) if start_col < 0: return False if Search(r'\bdecltype\s*$', text[0:start_col]): return True return False def CheckSectionSpacing(filename, clean_lines, class_info, linenum, error): """Checks for additional blank line issues related to sections. Currently the only thing checked here is blank line before protected/private. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. class_info: A _ClassInfo objects. linenum: The number of the line to check. error: The function to call with any errors found. """ # Skip checks if the class is small, where small means 25 lines or less. # 25 lines seems like a good cutoff since that's the usual height of # terminals, and any class that can't fit in one screen can't really # be considered "small". # # Also skip checks if we are on the first line. This accounts for # classes that look like # class Foo { public: ... }; # # If we didn't find the end of the class, last_line would be zero, # and the check will be skipped by the first condition. if (class_info.last_line - class_info.starting_linenum <= 24 or linenum <= class_info.starting_linenum): return matched = Match(r'\s*(public|protected|private):', clean_lines.lines[linenum]) if matched: # Issue warning if the line before public/protected/private was # not a blank line, but don't do this if the previous line contains # "class" or "struct". This can happen two ways: # - We are at the beginning of the class. # - We are forward-declaring an inner class that is semantically # private, but needed to be public for implementation reasons. # Also ignores cases where the previous line ends with a backslash as can be # common when defining classes in C macros. prev_line = clean_lines.lines[linenum - 1] if (not IsBlankLine(prev_line) and not Search(r'\b(class|struct)\b', prev_line) and not Search(r'\\$', prev_line)): # Try a bit harder to find the beginning of the class. This is to # account for multi-line base-specifier lists, e.g.: # class Derived # : public Base { end_class_head = class_info.starting_linenum for i in range(class_info.starting_linenum, linenum): if Search(r'\{\s*$', clean_lines.lines[i]): end_class_head = i break if end_class_head < linenum - 1: error(filename, linenum, 'whitespace/blank_line', 3, '"%s:" should be preceded by a blank line' % matched.group(1)) def GetPreviousNonBlankLine(clean_lines, linenum): """Return the most recent non-blank line and its line number. Args: clean_lines: A CleansedLines instance containing the file contents. linenum: The number of the line to check. Returns: A tuple with two elements. The first element is the contents of the last non-blank line before the current line, or the empty string if this is the first non-blank line. The second is the line number of that line, or -1 if this is the first non-blank line. """ prevlinenum = linenum - 1 while prevlinenum >= 0: prevline = clean_lines.elided[prevlinenum] if not IsBlankLine(prevline): # if not a blank line... return (prevline, prevlinenum) prevlinenum -= 1 return ('', -1) def CheckBraces(filename, clean_lines, linenum, error): """Looks for misplaced braces (e.g. at the end of line). Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # get rid of comments and strings if Match(r'\s*{\s*$', line): # We allow an open brace to start a line in the case where someone is using # braces in a block to explicitly create a new scope, which is commonly used # to control the lifetime of stack-allocated variables. Braces are also # used for brace initializers inside function calls. We don't detect this # perfectly: we just don't complain if the last non-whitespace character on # the previous non-blank line is ',', ';', ':', '(', '{', or '}', or if the # previous line starts a preprocessor block. We also allow a brace on the # following line if it is part of an array initialization and would not fit # within the 80 character limit of the preceding line. prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] if (not Search(r'[,;:}{(]\s*$', prevline) and not Match(r'\s*#', prevline) and not (GetLineWidth(prevline) > _line_length - 2 and '[]' in prevline)): error(filename, linenum, 'whitespace/braces', 4, '{ should almost always be at the end of the previous line') # An else clause should be on the same line as the preceding closing brace. if Match(r'\s*else\b\s*(?:if\b|\{|$)', line): prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] if Match(r'\s*}\s*$', prevline): error(filename, linenum, 'whitespace/newline', 4, 'An else should appear on the same line as the preceding }') # If braces come on one side of an else, they should be on both. # However, we have to worry about "else if" that spans multiple lines! if Search(r'else if\s*\(', line): # could be multi-line if brace_on_left = bool(Search(r'}\s*else if\s*\(', line)) # find the ( after the if pos = line.find('else if') pos = line.find('(', pos) if pos > 0: (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) brace_on_right = endline[endpos:].find('{') != -1 if brace_on_left != brace_on_right: # must be brace after if error(filename, linenum, 'readability/braces', 5, 'If an else has a brace on one side, it should have it on both') elif Search(r'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): error(filename, linenum, 'readability/braces', 5, 'If an else has a brace on one side, it should have it on both') # Likewise, an else should never have the else clause on the same line if Search(r'\belse [^\s{]', line) and not Search(r'\belse if\b', line): error(filename, linenum, 'whitespace/newline', 4, 'Else clause should never be on same line as else (use 2 lines)') # In the same way, a do/while should never be on one line if Match(r'\s*do [^\s{]', line): error(filename, linenum, 'whitespace/newline', 4, 'do/while clauses should not be on a single line') # Check single-line if/else bodies. The style guide says 'curly braces are not # required for single-line statements'. We additionally allow multi-line, # single statements, but we reject anything with more than one semicolon in # it. This means that the first semicolon after the if should be at the end of # its line, and the line after that should have an indent level equal to or # lower than the if. We also check for ambiguous if/else nesting without # braces. if_else_match = Search(r'\b(if\s*(|constexpr)\s*\(|else\b)', line) if if_else_match and not Match(r'\s*#', line): if_indent = GetIndentLevel(line) endline, endlinenum, endpos = line, linenum, if_else_match.end() if_match = Search(r'\bif\s*(|constexpr)\s*\(', line) if if_match: # This could be a multiline if condition, so find the end first. pos = if_match.end() - 1 (endline, endlinenum, endpos) = CloseExpression(clean_lines, linenum, pos) # Check for an opening brace, either directly after the if or on the next # line. If found, this isn't a single-statement conditional. if (not Match(r'\s*{', endline[endpos:]) and not (Match(r'\s*$', endline[endpos:]) and endlinenum < (len(clean_lines.elided) - 1) and Match(r'\s*{', clean_lines.elided[endlinenum + 1]))): while (endlinenum < len(clean_lines.elided) and ';' not in clean_lines.elided[endlinenum][endpos:]): endlinenum += 1 endpos = 0 if endlinenum < len(clean_lines.elided): endline = clean_lines.elided[endlinenum] # We allow a mix of whitespace and closing braces (e.g. for one-liner # methods) and a single \ after the semicolon (for macros) endpos = endline.find(';') if not Match(r';[\s}]*(\\?)$', endline[endpos:]): # Semicolon isn't the last character, there's something trailing. # Output a warning if the semicolon is not contained inside # a lambda expression. if not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}]*\}\s*\)*[;,]\s*$', endline): error(filename, linenum, 'readability/braces', 4, 'If/else bodies with multiple statements require braces') elif endlinenum < len(clean_lines.elided) - 1: # Make sure the next line is dedented next_line = clean_lines.elided[endlinenum + 1] next_indent = GetIndentLevel(next_line) # With ambiguous nested if statements, this will error out on the # if that *doesn't* match the else, regardless of whether it's the # inner one or outer one. if (if_match and Match(r'\s*else\b', next_line) and next_indent != if_indent): error(filename, linenum, 'readability/braces', 4, 'Else clause should be indented at the same level as if. ' 'Ambiguous nested if/else chains require braces.') elif next_indent > if_indent: error(filename, linenum, 'readability/braces', 4, 'If/else bodies with multiple statements require braces') def CheckTrailingSemicolon(filename, clean_lines, linenum, error): """Looks for redundant trailing semicolon. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Block bodies should not be followed by a semicolon. Due to C++11 # brace initialization, there are more places where semicolons are # required than not, so we explicitly list the allowed rules rather # than listing the disallowed ones. These are the places where "};" # should be replaced by just "}": # 1. Some flavor of block following closing parenthesis: # for (;;) {}; # while (...) {}; # switch (...) {}; # Function(...) {}; # if (...) {}; # if (...) else if (...) {}; # # 2. else block: # if (...) else {}; # # 3. const member function: # Function(...) const {}; # # 4. Block following some statement: # x = 42; # {}; # # 5. Block at the beginning of a function: # Function(...) { # {}; # } # # Note that naively checking for the preceding "{" will also match # braces inside multi-dimensional arrays, but this is fine since # that expression will not contain semicolons. # # 6. Block following another block: # while (true) {} # {}; # # 7. End of namespaces: # namespace {}; # # These semicolons seems far more common than other kinds of # redundant semicolons, possibly due to people converting classes # to namespaces. For now we do not warn for this case. # # Try matching case 1 first. match = Match(r'^(.*\)\s*)\{', line) if match: # Matched closing parenthesis (case 1). Check the token before the # matching opening parenthesis, and don't warn if it looks like a # macro. This avoids these false positives: # - macro that defines a base class # - multi-line macro that defines a base class # - macro that defines the whole class-head # # But we still issue warnings for macros that we know are safe to # warn, specifically: # - TEST, TEST_F, TEST_P, MATCHER, MATCHER_P # - TYPED_TEST # - INTERFACE_DEF # - EXCLUSIVE_LOCKS_REQUIRED, SHARED_LOCKS_REQUIRED, LOCKS_EXCLUDED: # # We implement a list of safe macros instead of a list of # unsafe macros, even though the latter appears less frequently in # google code and would have been easier to implement. This is because # the downside for getting the allowed checks wrong means some extra # semicolons, while the downside for getting disallowed checks wrong # would result in compile errors. # # In addition to macros, we also don't want to warn on # - Compound literals # - Lambdas # - alignas specifier with anonymous structs # - decltype closing_brace_pos = match.group(1).rfind(')') opening_parenthesis = ReverseCloseExpression( clean_lines, linenum, closing_brace_pos) if opening_parenthesis[2] > -1: line_prefix = opening_parenthesis[0][0:opening_parenthesis[2]] macro = Search(r'\b([A-Z_][A-Z0-9_]*)\s*$', line_prefix) func = Match(r'^(.*\])\s*$', line_prefix) if ((macro and macro.group(1) not in ( 'TEST', 'TEST_F', 'MATCHER', 'MATCHER_P', 'TYPED_TEST', 'EXCLUSIVE_LOCKS_REQUIRED', 'SHARED_LOCKS_REQUIRED', 'LOCKS_EXCLUDED', 'INTERFACE_DEF')) or (func and not Search(r'\boperator\s*\[\s*\]', func.group(1))) or Search(r'\b(?:struct|union)\s+alignas\s*$', line_prefix) or Search(r'\bdecltype$', line_prefix) or Search(r'\s+=\s*$', line_prefix)): match = None if (match and opening_parenthesis[1] > 1 and Search(r'\]\s*$', clean_lines.elided[opening_parenthesis[1] - 1])): # Multi-line lambda-expression match = None else: # Try matching cases 2-3. match = Match(r'^(.*(?:else|\)\s*const)\s*)\{', line) if not match: # Try matching cases 4-6. These are always matched on separate lines. # # Note that we can't simply concatenate the previous line to the # current line and do a single match, otherwise we may output # duplicate warnings for the blank line case: # if (cond) { # // blank line # } prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] if prevline and Search(r'[;{}]\s*$', prevline): match = Match(r'^(\s*)\{', line) # Check matching closing brace if match: (endline, endlinenum, endpos) = CloseExpression( clean_lines, linenum, len(match.group(1))) if endpos > -1 and Match(r'^\s*;', endline[endpos:]): # Current {} pair is eligible for semicolon check, and we have found # the redundant semicolon, output warning here. # # Note: because we are scanning forward for opening braces, and # outputting warnings for the matching closing brace, if there are # nested blocks with trailing semicolons, we will get the error # messages in reversed order. # We need to check the line forward for NOLINT raw_lines = clean_lines.raw_lines ParseNolintSuppressions(filename, raw_lines[endlinenum-1], endlinenum-1, error) ParseNolintSuppressions(filename, raw_lines[endlinenum], endlinenum, error) error(filename, endlinenum, 'readability/braces', 4, "You don't need a ; after a }") def CheckEmptyBlockBody(filename, clean_lines, linenum, error): """Look for empty loop/conditional body with only a single semicolon. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ # Search for loop keywords at the beginning of the line. Because only # whitespaces are allowed before the keywords, this will also ignore most # do-while-loops, since those lines should start with closing brace. # # We also check "if" blocks here, since an empty conditional block # is likely an error. line = clean_lines.elided[linenum] matched = Match(r'\s*(for|while|if)\s*\(', line) if matched: # Find the end of the conditional expression. (end_line, end_linenum, end_pos) = CloseExpression( clean_lines, linenum, line.find('(')) # Output warning if what follows the condition expression is a semicolon. # No warning for all other cases, including whitespace or newline, since we # have a separate check for semicolons preceded by whitespace. if end_pos >= 0 and Match(r';', end_line[end_pos:]): if matched.group(1) == 'if': error(filename, end_linenum, 'whitespace/empty_conditional_body', 5, 'Empty conditional bodies should use {}') else: error(filename, end_linenum, 'whitespace/empty_loop_body', 5, 'Empty loop bodies should use {} or continue') # Check for if statements that have completely empty bodies (no comments) # and no else clauses. if end_pos >= 0 and matched.group(1) == 'if': # Find the position of the opening { for the if statement. # Return without logging an error if it has no brackets. opening_linenum = end_linenum opening_line_fragment = end_line[end_pos:] # Loop until EOF or find anything that's not whitespace or opening {. while not Search(r'^\s*\{', opening_line_fragment): if Search(r'^(?!\s*$)', opening_line_fragment): # Conditional has no brackets. return opening_linenum += 1 if opening_linenum == len(clean_lines.elided): # Couldn't find conditional's opening { or any code before EOF. return opening_line_fragment = clean_lines.elided[opening_linenum] # Set opening_line (opening_line_fragment may not be entire opening line). opening_line = clean_lines.elided[opening_linenum] # Find the position of the closing }. opening_pos = opening_line_fragment.find('{') if opening_linenum == end_linenum: # We need to make opening_pos relative to the start of the entire line. opening_pos += end_pos (closing_line, closing_linenum, closing_pos) = CloseExpression( clean_lines, opening_linenum, opening_pos) if closing_pos < 0: return # Now construct the body of the conditional. This consists of the portion # of the opening line after the {, all lines until the closing line, # and the portion of the closing line before the }. if (clean_lines.raw_lines[opening_linenum] != CleanseComments(clean_lines.raw_lines[opening_linenum])): # Opening line ends with a comment, so conditional isn't empty. return if closing_linenum > opening_linenum: # Opening line after the {. Ignore comments here since we checked above. bodylist = list(opening_line[opening_pos+1:]) # All lines until closing line, excluding closing line, with comments. bodylist.extend(clean_lines.raw_lines[opening_linenum+1:closing_linenum]) # Closing line before the }. Won't (and can't) have comments. bodylist.append(clean_lines.elided[closing_linenum][:closing_pos-1]) body = '\n'.join(bodylist) else: # If statement has brackets and fits on a single line. body = opening_line[opening_pos+1:closing_pos-1] # Check if the body is empty if not _EMPTY_CONDITIONAL_BODY_PATTERN.search(body): return # The body is empty. Now make sure there's not an else clause. current_linenum = closing_linenum current_line_fragment = closing_line[closing_pos:] # Loop until EOF or find anything that's not whitespace or else clause. while Search(r'^\s*$|^(?=\s*else)', current_line_fragment): if Search(r'^(?=\s*else)', current_line_fragment): # Found an else clause, so don't log an error. return current_linenum += 1 if current_linenum == len(clean_lines.elided): break current_line_fragment = clean_lines.elided[current_linenum] # The body is empty and there's no else clause until EOF or other code. error(filename, end_linenum, 'whitespace/empty_if_body', 4, ('If statement had no body and no else clause')) def FindCheckMacro(line): """Find a replaceable CHECK-like macro. Args: line: line to search on. Returns: (macro name, start position), or (None, -1) if no replaceable macro is found. """ for macro in _CHECK_MACROS: i = line.find(macro) if i >= 0: # Find opening parenthesis. Do a regular expression match here # to make sure that we are matching the expected CHECK macro, as # opposed to some other macro that happens to contain the CHECK # substring. matched = Match(r'^(.*\b' + macro + r'\s*)\(', line) if not matched: continue return (macro, len(matched.group(1))) return (None, -1) def CheckCheck(filename, clean_lines, linenum, error): """Checks the use of CHECK and EXPECT macros. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ # Decide the set of replacement macros that should be suggested lines = clean_lines.elided (check_macro, start_pos) = FindCheckMacro(lines[linenum]) if not check_macro: return # Find end of the boolean expression by matching parentheses (last_line, end_line, end_pos) = CloseExpression( clean_lines, linenum, start_pos) if end_pos < 0: return # If the check macro is followed by something other than a # semicolon, assume users will log their own custom error messages # and don't suggest any replacements. if not Match(r'\s*;', last_line[end_pos:]): return if linenum == end_line: expression = lines[linenum][start_pos + 1:end_pos - 1] else: expression = lines[linenum][start_pos + 1:] for i in xrange(linenum + 1, end_line): expression += lines[i] expression += last_line[0:end_pos - 1] # Parse expression so that we can take parentheses into account. # This avoids false positives for inputs like "CHECK((a < 4) == b)", # which is not replaceable by CHECK_LE. lhs = '' rhs = '' operator = None while expression: matched = Match(r'^\s*(<<|<<=|>>|>>=|->\*|->|&&|\|\||' r'==|!=|>=|>|<=|<|\()(.*)$', expression) if matched: token = matched.group(1) if token == '(': # Parenthesized operand expression = matched.group(2) (end, _) = FindEndOfExpressionInLine(expression, 0, ['(']) if end < 0: return # Unmatched parenthesis lhs += '(' + expression[0:end] expression = expression[end:] elif token in ('&&', '||'): # Logical and/or operators. This means the expression # contains more than one term, for example: # CHECK(42 < a && a < b); # # These are not replaceable with CHECK_LE, so bail out early. return elif token in ('<<', '<<=', '>>', '>>=', '->*', '->'): # Non-relational operator lhs += token expression = matched.group(2) else: # Relational operator operator = token rhs = matched.group(2) break else: # Unparenthesized operand. Instead of appending to lhs one character # at a time, we do another regular expression match to consume several # characters at once if possible. Trivial benchmark shows that this # is more efficient when the operands are longer than a single # character, which is generally the case. matched = Match(r'^([^-=!<>()&|]+)(.*)$', expression) if not matched: matched = Match(r'^(\s*\S)(.*)$', expression) if not matched: break lhs += matched.group(1) expression = matched.group(2) # Only apply checks if we got all parts of the boolean expression if not (lhs and operator and rhs): return # Check that rhs do not contain logical operators. We already know # that lhs is fine since the loop above parses out && and ||. if rhs.find('&&') > -1 or rhs.find('||') > -1: return # At least one of the operands must be a constant literal. This is # to avoid suggesting replacements for unprintable things like # CHECK(variable != iterator) # # The following pattern matches decimal, hex integers, strings, and # characters (in that order). lhs = lhs.strip() rhs = rhs.strip() match_constant = r'^([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')$' if Match(match_constant, lhs) or Match(match_constant, rhs): # Note: since we know both lhs and rhs, we can provide a more # descriptive error message like: # Consider using CHECK_EQ(x, 42) instead of CHECK(x == 42) # Instead of: # Consider using CHECK_EQ instead of CHECK(a == b) # # We are still keeping the less descriptive message because if lhs # or rhs gets long, the error message might become unreadable. error(filename, linenum, 'readability/check', 2, 'Consider using %s instead of %s(a %s b)' % ( _CHECK_REPLACEMENT[check_macro][operator], check_macro, operator)) def CheckAltTokens(filename, clean_lines, linenum, error): """Check alternative keywords being used in boolean expressions. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Avoid preprocessor lines if Match(r'^\s*#', line): return # Last ditch effort to avoid multi-line comments. This will not help # if the comment started before the current line or ended after the # current line, but it catches most of the false positives. At least, # it provides a way to workaround this warning for people who use # multi-line comments in preprocessor macros. # # TODO(unknown): remove this once cpplint has better support for # multi-line comments. if line.find('/*') >= 0 or line.find('*/') >= 0: return for match in _ALT_TOKEN_REPLACEMENT_PATTERN.finditer(line): error(filename, linenum, 'readability/alt_tokens', 2, 'Use operator %s instead of %s' % ( _ALT_TOKEN_REPLACEMENT[match.group(1)], match.group(1))) def GetLineWidth(line): """Determines the width of the line in column positions. Args: line: A string, which may be a Unicode string. Returns: The width of the line in column positions, accounting for Unicode combining characters and wide characters. """ if isinstance(line, unicode): width = 0 for uc in unicodedata.normalize('NFC', line): if unicodedata.east_asian_width(uc) in ('W', 'F'): width += 2 elif not unicodedata.combining(uc): # Issue 337 # https://mail.python.org/pipermail/python-list/2012-August/628809.html if (sys.version_info.major, sys.version_info.minor) <= (3, 2): # https://github.com/python/cpython/blob/2.7/Include/unicodeobject.h#L81 is_wide_build = sysconfig.get_config_var("Py_UNICODE_SIZE") >= 4 # https://github.com/python/cpython/blob/2.7/Objects/unicodeobject.c#L564 is_low_surrogate = 0xDC00 <= ord(uc) <= 0xDFFF if not is_wide_build and is_low_surrogate: width -= 1 width += 1 return width else: return len(line) def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, error): """Checks rules from the 'C++ style rules' section of cppguide.html. Most of these rules are hard to test (naming, comment style), but we do what we can. In particular we check for 2-space indents, line lengths, tab usage, spaces inside code, etc. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. file_extension: The extension (without the dot) of the filename. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: The function to call with any errors found. """ # Don't use "elided" lines here, otherwise we can't check commented lines. # Don't want to use "raw" either, because we don't want to check inside C++11 # raw strings, raw_lines = clean_lines.lines_without_raw_strings line = raw_lines[linenum] prev = raw_lines[linenum - 1] if linenum > 0 else '' if line.find('\t') != -1: error(filename, linenum, 'whitespace/tab', 1, 'Tab found; better to use spaces') # One or three blank spaces at the beginning of the line is weird; it's # hard to reconcile that with 2-space indents. # NOTE: here are the conditions rob pike used for his tests. Mine aren't # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces # if(RLENGTH > 20) complain = 0; # if(match($0, " +(error|private|public|protected):")) complain = 0; # if(match(prev, "&& *$")) complain = 0; # if(match(prev, "\\|\\| *$")) complain = 0; # if(match(prev, "[\",=><] *$")) complain = 0; # if(match($0, " <<")) complain = 0; # if(match(prev, " +for \\(")) complain = 0; # if(prevodd && match(prevprev, " +for \\(")) complain = 0; scope_or_label_pattern = r'\s*(?:public|private|protected|signals)(?:\s+(?:slots\s*)?)?:\s*\\?$' classinfo = nesting_state.InnermostClass() initial_spaces = 0 cleansed_line = clean_lines.elided[linenum] while initial_spaces < len(line) and line[initial_spaces] == ' ': initial_spaces += 1 # There are certain situations we allow one space, notably for # section labels, and also lines containing multi-line raw strings. # We also don't check for lines that look like continuation lines # (of lines ending in double quotes, commas, equals, or angle brackets) # because the rules for how to indent those are non-trivial. if (not Search(r'[",=><] *$', prev) and (initial_spaces == 1 or initial_spaces == 3) and not Match(scope_or_label_pattern, cleansed_line) and not (clean_lines.raw_lines[linenum] != line and Match(r'^\s*""', line))): error(filename, linenum, 'whitespace/indent', 3, 'Weird number of spaces at line-start. ' 'Are you using a 2-space indent?') if line and line[-1].isspace(): error(filename, linenum, 'whitespace/end_of_line', 4, 'Line ends in whitespace. Consider deleting these extra spaces.') # Check if the line is a header guard. is_header_guard = False if IsHeaderExtension(file_extension): cppvar = GetHeaderGuardCPPVariable(filename) if (line.startswith('#ifndef %s' % cppvar) or line.startswith('#define %s' % cppvar) or line.startswith('#endif // %s' % cppvar)): is_header_guard = True # #include lines and header guards can be long, since there's no clean way to # split them. # # URLs can be long too. It's possible to split these, but it makes them # harder to cut&paste. # # The "$Id:...$" comment may also get very long without it being the # developers fault. # # Doxygen documentation copying can get pretty long when using an overloaded # function declaration if (not line.startswith('#include') and not is_header_guard and not Match(r'^\s*//.*http(s?)://\S*$', line) and not Match(r'^\s*//\s*[^\s]*$', line) and not Match(r'^// \$Id:.*#[0-9]+ \$$', line) and not Match(r'^\s*/// [@\\](copydoc|copydetails|copybrief) .*$', line)): line_width = GetLineWidth(line) if line_width > _line_length: error(filename, linenum, 'whitespace/line_length', 2, 'Lines should be <= %i characters long' % _line_length) if (cleansed_line.count(';') > 1 and # allow simple single line lambdas not Match(r'^[^{};]*\[[^\[\]]*\][^{}]*\{[^{}\n\r]*\}', line) and # for loops are allowed two ;'s (and may run over two lines). cleansed_line.find('for') == -1 and (GetPreviousNonBlankLine(clean_lines, linenum)[0].find('for') == -1 or GetPreviousNonBlankLine(clean_lines, linenum)[0].find(';') != -1) and # It's ok to have many commands in a switch case that fits in 1 line not ((cleansed_line.find('case ') != -1 or cleansed_line.find('default:') != -1) and cleansed_line.find('break;') != -1)): error(filename, linenum, 'whitespace/newline', 0, 'More than one command on the same line') # Some more style checks CheckBraces(filename, clean_lines, linenum, error) CheckTrailingSemicolon(filename, clean_lines, linenum, error) CheckEmptyBlockBody(filename, clean_lines, linenum, error) CheckSpacing(filename, clean_lines, linenum, nesting_state, error) CheckOperatorSpacing(filename, clean_lines, linenum, error) CheckParenthesisSpacing(filename, clean_lines, linenum, error) CheckCommaSpacing(filename, clean_lines, linenum, error) CheckBracesSpacing(filename, clean_lines, linenum, nesting_state, error) CheckSpacingForFunctionCall(filename, clean_lines, linenum, error) CheckCheck(filename, clean_lines, linenum, error) CheckAltTokens(filename, clean_lines, linenum, error) classinfo = nesting_state.InnermostClass() if classinfo: CheckSectionSpacing(filename, clean_lines, classinfo, linenum, error) _RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$') # Matches the first component of a filename delimited by -s and _s. That is: # _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo.cc').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo-bar_baz.cc').group(0) == 'foo' # _RE_FIRST_COMPONENT.match('foo_bar-baz.cc').group(0) == 'foo' _RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+') def _DropCommonSuffixes(filename): """Drops common suffixes like _test.cc or -inl.h from filename. For example: >>> _DropCommonSuffixes('foo/foo-inl.h') 'foo/foo' >>> _DropCommonSuffixes('foo/bar/foo.cc') 'foo/bar/foo' >>> _DropCommonSuffixes('foo/foo_internal.h') 'foo/foo' >>> _DropCommonSuffixes('foo/foo_unusualinternal.h') 'foo/foo_unusualinternal' Args: filename: The input filename. Returns: The filename with the common suffix removed. """ for suffix in itertools.chain( ('%s.%s' % (test_suffix.lstrip('_'), ext) for test_suffix, ext in itertools.product(_test_suffixes, GetNonHeaderExtensions())), ('%s.%s' % (suffix, ext) for suffix, ext in itertools.product(['inl', 'imp', 'internal'], GetHeaderExtensions()))): if (filename.endswith(suffix) and len(filename) > len(suffix) and filename[-len(suffix) - 1] in ('-', '_')): return filename[:-len(suffix) - 1] return os.path.splitext(filename)[0] def _ClassifyInclude(fileinfo, include, used_angle_brackets, include_order="default"): """Figures out what kind of header 'include' is. Args: fileinfo: The current file cpplint is running over. A FileInfo instance. include: The path to a #included file. used_angle_brackets: True if the #include used <> rather than "". include_order: "default" or other value allowed in program arguments Returns: One of the _XXX_HEADER constants. For example: >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'stdio.h', True) _C_SYS_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'string', True) _CPP_SYS_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', True, "standardcfirst") _OTHER_SYS_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/foo.h', False) _LIKELY_MY_HEADER >>> _ClassifyInclude(FileInfo('foo/foo_unknown_extension.cc'), ... 'bar/foo_other_ext.h', False) _POSSIBLE_MY_HEADER >>> _ClassifyInclude(FileInfo('foo/foo.cc'), 'foo/bar.h', False) _OTHER_HEADER """ # This is a list of all standard c++ header files, except # those already checked for above. is_cpp_header = include in _CPP_HEADERS # Mark include as C header if in list or in a known folder for standard-ish C headers. is_std_c_header = (include_order == "default") or (include in _C_HEADERS # additional linux glibc header folders or Search(r'(?:%s)\/.*\.h' % "|".join(C_STANDARD_HEADER_FOLDERS), include)) # Headers with C++ extensions shouldn't be considered C system headers is_system = used_angle_brackets and not os.path.splitext(include)[1] in ['.hpp', '.hxx', '.h++'] if is_system: if is_cpp_header: return _CPP_SYS_HEADER if is_std_c_header: return _C_SYS_HEADER else: return _OTHER_SYS_HEADER # If the target file and the include we're checking share a # basename when we drop common extensions, and the include # lives in . , then it's likely to be owned by the target file. target_dir, target_base = ( os.path.split(_DropCommonSuffixes(fileinfo.RepositoryName()))) include_dir, include_base = os.path.split(_DropCommonSuffixes(include)) target_dir_pub = os.path.normpath(target_dir + '/../public') target_dir_pub = target_dir_pub.replace('\\', '/') if target_base == include_base and ( include_dir == target_dir or include_dir == target_dir_pub): return _LIKELY_MY_HEADER # If the target and include share some initial basename # component, it's possible the target is implementing the # include, so it's allowed to be first, but we'll never # complain if it's not there. target_first_component = _RE_FIRST_COMPONENT.match(target_base) include_first_component = _RE_FIRST_COMPONENT.match(include_base) if (target_first_component and include_first_component and target_first_component.group(0) == include_first_component.group(0)): return _POSSIBLE_MY_HEADER return _OTHER_HEADER def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): """Check rules that are applicable to #include lines. Strings on #include lines are NOT removed from elided line, to make certain tasks easier. However, to prevent false positives, checks applicable to #include lines in CheckLanguage must be put here. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. include_state: An _IncludeState instance in which the headers are inserted. error: The function to call with any errors found. """ fileinfo = FileInfo(filename) line = clean_lines.lines[linenum] # "include" should use the new style "foo/bar.h" instead of just "bar.h" # Only do this check if the included header follows google naming # conventions. If not, assume that it's a 3rd party API that # requires special include conventions. # # We also make an exception for Lua headers, which follow google # naming convention but not the include convention. match = Match(r'#include\s*"([^/]+\.h)"', line) if match and not _THIRD_PARTY_HEADERS_PATTERN.match(match.group(1)): error(filename, linenum, 'build/include_subdir', 4, 'Include the directory when naming .h files') # we shouldn't include a file more than once. actually, there are a # handful of instances where doing so is okay, but in general it's # not. match = _RE_PATTERN_INCLUDE.search(line) if match: include = match.group(2) used_angle_brackets = (match.group(1) == '<') duplicate_line = include_state.FindHeader(include) if duplicate_line >= 0: error(filename, linenum, 'build/include', 4, '"%s" already included at %s:%s' % (include, filename, duplicate_line)) return for extension in GetNonHeaderExtensions(): if (include.endswith('.' + extension) and os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): error(filename, linenum, 'build/include', 4, 'Do not include .' + extension + ' files from other packages') return # We DO want to include a 3rd party looking header if it matches the # filename. Otherwise we get an erroneous error "...should include its # header" error later. third_src_header = False for ext in GetHeaderExtensions(): basefilename = filename[0:len(filename) - len(fileinfo.Extension())] headerfile = basefilename + '.' + ext headername = FileInfo(headerfile).RepositoryName() if headername in include or include in headername: third_src_header = True break if third_src_header or not _THIRD_PARTY_HEADERS_PATTERN.match(include): include_state.include_list[-1].append((include, linenum)) # We want to ensure that headers appear in the right order: # 1) for foo.cc, foo.h (preferred location) # 2) c system files # 3) cpp system files # 4) for foo.cc, foo.h (deprecated location) # 5) other google headers # # We classify each include statement as one of those 5 types # using a number of techniques. The include_state object keeps # track of the highest type seen, and complains if we see a # lower type after that. error_message = include_state.CheckNextIncludeOrder( _ClassifyInclude(fileinfo, include, used_angle_brackets, _include_order)) if error_message: error(filename, linenum, 'build/include_order', 4, '%s. Should be: %s.h, c system, c++ system, other.' % (error_message, fileinfo.BaseName())) canonical_include = include_state.CanonicalizeAlphabeticalOrder(include) if not include_state.IsInAlphabeticalOrder( clean_lines, linenum, canonical_include): error(filename, linenum, 'build/include_alpha', 4, 'Include "%s" not in alphabetical order' % include) include_state.SetLastHeader(canonical_include) def _GetTextInside(text, start_pattern): r"""Retrieves all the text between matching open and close parentheses. Given a string of lines and a regular expression string, retrieve all the text following the expression and between opening punctuation symbols like (, [, or {, and the matching close-punctuation symbol. This properly nested occurrences of the punctuations, so for the text like printf(a(), b(c())); a call to _GetTextInside(text, r'printf\(') will return 'a(), b(c())'. start_pattern must match string having an open punctuation symbol at the end. Args: text: The lines to extract text. Its comments and strings must be elided. It can be single line and can span multiple lines. start_pattern: The regexp string indicating where to start extracting the text. Returns: The extracted text. None if either the opening string or ending punctuation could not be found. """ # TODO(unknown): Audit cpplint.py to see what places could be profitably # rewritten to use _GetTextInside (and use inferior regexp matching today). # Give opening punctuations to get the matching close-punctuations. matching_punctuation = {'(': ')', '{': '}', '[': ']'} closing_punctuation = set(itervalues(matching_punctuation)) # Find the position to start extracting text. match = re.search(start_pattern, text, re.M) if not match: # start_pattern not found in text. return None start_position = match.end(0) assert start_position > 0, ( 'start_pattern must ends with an opening punctuation.') assert text[start_position - 1] in matching_punctuation, ( 'start_pattern must ends with an opening punctuation.') # Stack of closing punctuations we expect to have in text after position. punctuation_stack = [matching_punctuation[text[start_position - 1]]] position = start_position while punctuation_stack and position < len(text): if text[position] == punctuation_stack[-1]: punctuation_stack.pop() elif text[position] in closing_punctuation: # A closing punctuation without matching opening punctuations. return None elif text[position] in matching_punctuation: punctuation_stack.append(matching_punctuation[text[position]]) position += 1 if punctuation_stack: # Opening punctuations left without matching close-punctuations. return None # punctuations match. return text[start_position:position - 1] # Patterns for matching call-by-reference parameters. # # Supports nested templates up to 2 levels deep using this messy pattern: # < (?: < (?: < [^<>]* # > # | [^<>] )* # > # | [^<>] )* # > _RE_PATTERN_IDENT = r'[_a-zA-Z]\w*' # =~ [[:alpha:]][[:alnum:]]* _RE_PATTERN_TYPE = ( r'(?:const\s+)?(?:typename\s+|class\s+|struct\s+|union\s+|enum\s+)?' r'(?:\w|' r'\s*<(?:<(?:<[^<>]*>|[^<>])*>|[^<>])*>|' r'::)+') # A call-by-reference parameter ends with '& identifier'. _RE_PATTERN_REF_PARAM = re.compile( r'(' + _RE_PATTERN_TYPE + r'(?:\s*(?:\bconst\b|[*]))*\s*' r'&\s*' + _RE_PATTERN_IDENT + r')\s*(?:=[^,()]+)?[,)]') # A call-by-const-reference parameter either ends with 'const& identifier' # or looks like 'const type& identifier' when 'type' is atomic. _RE_PATTERN_CONST_REF_PARAM = ( r'(?:.*\s*\bconst\s*&\s*' + _RE_PATTERN_IDENT + r'|const\s+' + _RE_PATTERN_TYPE + r'\s*&\s*' + _RE_PATTERN_IDENT + r')') # Stream types. _RE_PATTERN_REF_STREAM_PARAM = ( r'(?:.*stream\s*&\s*' + _RE_PATTERN_IDENT + r')') def CheckLanguage(filename, clean_lines, linenum, file_extension, include_state, nesting_state, error): """Checks rules from the 'C++ language rules' section of cppguide.html. Some of these rules are hard to test (function overloading, using uint32 inappropriately), but we do the best we can. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. file_extension: The extension (without the dot) of the filename. include_state: An _IncludeState instance in which the headers are inserted. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: The function to call with any errors found. """ # If the line is empty or consists of entirely a comment, no need to # check it. line = clean_lines.elided[linenum] if not line: return match = _RE_PATTERN_INCLUDE.search(line) if match: CheckIncludeLine(filename, clean_lines, linenum, include_state, error) return # Reset include state across preprocessor directives. This is meant # to silence warnings for conditional includes. match = Match(r'^\s*#\s*(if|ifdef|ifndef|elif|else|endif)\b', line) if match: include_state.ResetSection(match.group(1)) # Perform other checks now that we are sure that this is not an include line CheckCasts(filename, clean_lines, linenum, error) CheckGlobalStatic(filename, clean_lines, linenum, error) CheckPrintf(filename, clean_lines, linenum, error) if IsHeaderExtension(file_extension): # TODO(unknown): check that 1-arg constructors are explicit. # How to tell it's a constructor? # (handled in CheckForNonStandardConstructs for now) # TODO(unknown): check that classes declare or disable copy/assign # (level 1 error) pass # Check if people are using the verboten C basic types. The only exception # we regularly allow is "unsigned short port" for port. if Search(r'\bshort port\b', line): if not Search(r'\bunsigned short port\b', line): error(filename, linenum, 'runtime/int', 4, 'Use "unsigned short" for ports, not "short"') else: match = Search(r'\b(short|long(?! +double)|long long)\b', line) if match: error(filename, linenum, 'runtime/int', 4, 'Use int16/int64/etc, rather than the C type %s' % match.group(1)) # Check if some verboten operator overloading is going on # TODO(unknown): catch out-of-line unary operator&: # class X {}; # int operator&(const X& x) { return 42; } // unary operator& # The trick is it's hard to tell apart from binary operator&: # class Y { int operator&(const Y& x) { return 23; } }; // binary operator& if Search(r'\boperator\s*&\s*\(\s*\)', line): error(filename, linenum, 'runtime/operator', 4, 'Unary operator& is dangerous. Do not use it.') # Check for suspicious usage of "if" like # } if (a == b) { if Search(r'\}\s*if\s*\(', line): error(filename, linenum, 'readability/braces', 4, 'Did you mean "else if"? If not, start a new line for "if".') # Check for potential format string bugs like printf(foo). # We constrain the pattern not to pick things like DocidForPrintf(foo). # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str()) # TODO(unknown): Catch the following case. Need to change the calling # convention of the whole function to process multiple line to handle it. # printf( # boy_this_is_a_really_long_variable_that_cannot_fit_on_the_prev_line); printf_args = _GetTextInside(line, r'(?i)\b(string)?printf\s*\(') if printf_args: match = Match(r'([\w.\->()]+)$', printf_args) if match and match.group(1) != '__VA_ARGS__': function_name = re.search(r'\b((?:string)?printf)\s*\(', line, re.I).group(1) error(filename, linenum, 'runtime/printf', 4, 'Potential format string bug. Do %s("%%s", %s) instead.' % (function_name, match.group(1))) # Check for potential memset bugs like memset(buf, sizeof(buf), 0). match = Search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line) if match and not Match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", match.group(2)): error(filename, linenum, 'runtime/memset', 4, 'Did you mean "memset(%s, 0, %s)"?' % (match.group(1), match.group(2))) if Search(r'\busing namespace\b', line): if Search(r'\bliterals\b', line): error(filename, linenum, 'build/namespaces_literals', 5, 'Do not use namespace using-directives. ' 'Use using-declarations instead.') else: error(filename, linenum, 'build/namespaces', 5, 'Do not use namespace using-directives. ' 'Use using-declarations instead.') # Detect variable-length arrays. match = Match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line) if (match and match.group(2) != 'return' and match.group(2) != 'delete' and match.group(3).find(']') == -1): # Split the size using space and arithmetic operators as delimiters. # If any of the resulting tokens are not compile time constants then # report the error. tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', match.group(3)) is_const = True skip_next = False for tok in tokens: if skip_next: skip_next = False continue if Search(r'sizeof\(.+\)', tok): continue if Search(r'arraysize\(\w+\)', tok): continue tok = tok.lstrip('(') tok = tok.rstrip(')') if not tok: continue if Match(r'\d+', tok): continue if Match(r'0[xX][0-9a-fA-F]+', tok): continue if Match(r'k[A-Z0-9]\w*', tok): continue if Match(r'(.+::)?k[A-Z0-9]\w*', tok): continue if Match(r'(.+::)?[A-Z][A-Z0-9_]*', tok): continue # A catch all for tricky sizeof cases, including 'sizeof expression', # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)' # requires skipping the next token because we split on ' ' and '*'. if tok.startswith('sizeof'): skip_next = True continue is_const = False break if not is_const: error(filename, linenum, 'runtime/arrays', 1, 'Do not use variable-length arrays. Use an appropriately named ' "('k' followed by CamelCase) compile-time constant for the size.") # Check for use of unnamed namespaces in header files. Registration # macros are typically OK, so we allow use of "namespace {" on lines # that end with backslashes. if (IsHeaderExtension(file_extension) and Search(r'\bnamespace\s*{', line) and line[-1] != '\\'): error(filename, linenum, 'build/namespaces_headers', 4, 'Do not use unnamed namespaces in header files. See ' 'https://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' ' for more information.') def CheckGlobalStatic(filename, clean_lines, linenum, error): """Check for unsafe global or static objects. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Match two lines at a time to support multiline declarations if linenum + 1 < clean_lines.NumLines() and not Search(r'[;({]', line): line += clean_lines.elided[linenum + 1].strip() # Check for people declaring static/global STL strings at the top level. # This is dangerous because the C++ language does not guarantee that # globals with constructors are initialized before the first access, and # also because globals can be destroyed when some threads are still running. # TODO(unknown): Generalize this to also find static unique_ptr instances. # TODO(unknown): File bugs for clang-tidy to find these. match = Match( r'((?:|static +)(?:|const +))(?::*std::)?string( +const)? +' r'([a-zA-Z0-9_:]+)\b(.*)', line) # Remove false positives: # - String pointers (as opposed to values). # string *pointer # const string *pointer # string const *pointer # string *const pointer # # - Functions and template specializations. # string Function(... # string Class::Method(... # # - Operators. These are matched separately because operator names # cross non-word boundaries, and trying to match both operators # and functions at the same time would decrease accuracy of # matching identifiers. # string Class::operator*() if (match and not Search(r'\bstring\b(\s+const)?\s*[\*\&]\s*(const\s+)?\w', line) and not Search(r'\boperator\W', line) and not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)*\s*\(([^"]|$)', match.group(4))): if Search(r'\bconst\b', line): error(filename, linenum, 'runtime/string', 4, 'For a static/global string constant, use a C style string ' 'instead: "%schar%s %s[]".' % (match.group(1), match.group(2) or '', match.group(3))) else: error(filename, linenum, 'runtime/string', 4, 'Static/global string variables are not permitted.') if (Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line) or Search(r'\b([A-Za-z0-9_]*_)\(CHECK_NOTNULL\(\1\)\)', line)): error(filename, linenum, 'runtime/init', 4, 'You seem to be initializing a member variable with itself.') def CheckPrintf(filename, clean_lines, linenum, error): """Check for printf related issues. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # When snprintf is used, the second argument shouldn't be a literal. match = Search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line) if match and match.group(2) != '0': # If 2nd arg is zero, snprintf is used to calculate size. error(filename, linenum, 'runtime/printf', 3, 'If you can, use sizeof(%s) instead of %s as the 2nd arg ' 'to snprintf.' % (match.group(1), match.group(2))) # Check if some verboten C functions are being used. if Search(r'\bsprintf\s*\(', line): error(filename, linenum, 'runtime/printf', 5, 'Never use sprintf. Use snprintf instead.') match = Search(r'\b(strcpy|strcat)\s*\(', line) if match: error(filename, linenum, 'runtime/printf', 4, 'Almost always, snprintf is better than %s' % match.group(1)) def IsDerivedFunction(clean_lines, linenum): """Check if current line contains an inherited function. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. Returns: True if current line contains a function with "override" virt-specifier. """ # Scan back a few lines for start of current function for i in xrange(linenum, max(-1, linenum - 10), -1): match = Match(r'^([^()]*\w+)\(', clean_lines.elided[i]) if match: # Look for "override" after the matching closing parenthesis line, _, closing_paren = CloseExpression( clean_lines, i, len(match.group(1))) return (closing_paren >= 0 and Search(r'\boverride\b', line[closing_paren:])) return False def IsOutOfLineMethodDefinition(clean_lines, linenum): """Check if current line contains an out-of-line method definition. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. Returns: True if current line contains an out-of-line method definition. """ # Scan back a few lines for start of current function for i in xrange(linenum, max(-1, linenum - 10), -1): if Match(r'^([^()]*\w+)\(', clean_lines.elided[i]): return Match(r'^[^()]*\w+::\w+\(', clean_lines.elided[i]) is not None return False def IsInitializerList(clean_lines, linenum): """Check if current line is inside constructor initializer list. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. Returns: True if current line appears to be inside constructor initializer list, False otherwise. """ for i in xrange(linenum, 1, -1): line = clean_lines.elided[i] if i == linenum: remove_function_body = Match(r'^(.*)\{\s*$', line) if remove_function_body: line = remove_function_body.group(1) if Search(r'\s:\s*\w+[({]', line): # A lone colon tend to indicate the start of a constructor # initializer list. It could also be a ternary operator, which # also tend to appear in constructor initializer lists as # opposed to parameter lists. return True if Search(r'\}\s*,\s*$', line): # A closing brace followed by a comma is probably the end of a # brace-initialized member in constructor initializer list. return True if Search(r'[{};]\s*$', line): # Found one of the following: # - A closing brace or semicolon, probably the end of the previous # function. # - An opening brace, probably the start of current class or namespace. # # Current line is probably not inside an initializer list since # we saw one of those things without seeing the starting colon. return False # Got to the beginning of the file without seeing the start of # constructor initializer list. return False def CheckForNonConstReference(filename, clean_lines, linenum, nesting_state, error): """Check for non-const references. Separate from CheckLanguage since it scans backwards from current line, instead of scanning forward. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: The function to call with any errors found. """ # Do nothing if there is no '&' on current line. line = clean_lines.elided[linenum] if '&' not in line: return # If a function is inherited, current function doesn't have much of # a choice, so any non-const references should not be blamed on # derived function. if IsDerivedFunction(clean_lines, linenum): return # Don't warn on out-of-line method definitions, as we would warn on the # in-line declaration, if it isn't marked with 'override'. if IsOutOfLineMethodDefinition(clean_lines, linenum): return # Long type names may be broken across multiple lines, usually in one # of these forms: # LongType # ::LongTypeContinued &identifier # LongType:: # LongTypeContinued &identifier # LongType< # ...>::LongTypeContinued &identifier # # If we detected a type split across two lines, join the previous # line to current line so that we can match const references # accordingly. # # Note that this only scans back one line, since scanning back # arbitrary number of lines would be expensive. If you have a type # that spans more than 2 lines, please use a typedef. if linenum > 1: previous = None if Match(r'\s*::(?:[\w<>]|::)+\s*&\s*\S', line): # previous_line\n + ::current_line previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+[\w<>])\s*$', clean_lines.elided[linenum - 1]) elif Match(r'\s*[a-zA-Z_]([\w<>]|::)+\s*&\s*\S', line): # previous_line::\n + current_line previous = Search(r'\b((?:const\s*)?(?:[\w<>]|::)+::)\s*$', clean_lines.elided[linenum - 1]) if previous: line = previous.group(1) + line.lstrip() else: # Check for templated parameter that is split across multiple lines endpos = line.rfind('>') if endpos > -1: (_, startline, startpos) = ReverseCloseExpression( clean_lines, linenum, endpos) if startpos > -1 and startline < linenum: # Found the matching < on an earlier line, collect all # pieces up to current line. line = '' for i in xrange(startline, linenum + 1): line += clean_lines.elided[i].strip() # Check for non-const references in function parameters. A single '&' may # found in the following places: # inside expression: binary & for bitwise AND # inside expression: unary & for taking the address of something # inside declarators: reference parameter # We will exclude the first two cases by checking that we are not inside a # function body, including one that was just introduced by a trailing '{'. # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. if (nesting_state.previous_stack_top and not (isinstance(nesting_state.previous_stack_top, _ClassInfo) or isinstance(nesting_state.previous_stack_top, _NamespaceInfo))): # Not at toplevel, not within a class, and not within a namespace return # Avoid initializer lists. We only need to scan back from the # current line for something that starts with ':'. # # We don't need to check the current line, since the '&' would # appear inside the second set of parentheses on the current line as # opposed to the first set. if linenum > 0: for i in xrange(linenum - 1, max(0, linenum - 10), -1): previous_line = clean_lines.elided[i] if not Search(r'[),]\s*$', previous_line): break if Match(r'^\s*:\s+\S', previous_line): return # Avoid preprocessors if Search(r'\\\s*$', line): return # Avoid constructor initializer lists if IsInitializerList(clean_lines, linenum): return # We allow non-const references in a few standard places, like functions # called "swap()" or iostream operators like "<<" or ">>". Do not check # those function parameters. # # We also accept & in static_assert, which looks like a function but # it's actually a declaration expression. allowed_functions = (r'(?:[sS]wap(?:<\w:+>)?|' r'operator\s*[<>][<>]|' r'static_assert|COMPILE_ASSERT' r')\s*\(') if Search(allowed_functions, line): return elif not Search(r'\S+\([^)]*$', line): # Don't see an allowed function on this line. Actually we # didn't see any function name on this line, so this is likely a # multi-line parameter list. Try a bit harder to catch this case. for i in xrange(2): if (linenum > i and Search(allowed_functions, clean_lines.elided[linenum - i - 1])): return decls = ReplaceAll(r'{[^}]*}', ' ', line) # exclude function body for parameter in re.findall(_RE_PATTERN_REF_PARAM, decls): if (not Match(_RE_PATTERN_CONST_REF_PARAM, parameter) and not Match(_RE_PATTERN_REF_STREAM_PARAM, parameter)): error(filename, linenum, 'runtime/references', 2, 'Is this a non-const reference? ' 'If so, make const or use a pointer: ' + ReplaceAll(' *<', '<', parameter)) def CheckCasts(filename, clean_lines, linenum, error): """Various cast related checks. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] # Check to see if they're using an conversion function cast. # I just try to capture the most common basic types, though there are more. # Parameterless conversion functions, such as bool(), are allowed as they are # probably a member operator declaration or default constructor. match = Search( r'(\bnew\s+(?:const\s+)?|\S<\s*(?:const\s+)?)?\b' r'(int|float|double|bool|char|int32|uint32|int64|uint64)' r'(\([^)].*)', line) expecting_function = ExpectingFunctionArgs(clean_lines, linenum) if match and not expecting_function: matched_type = match.group(2) # matched_new_or_template is used to silence two false positives: # - New operators # - Template arguments with function types # # For template arguments, we match on types immediately following # an opening bracket without any spaces. This is a fast way to # silence the common case where the function type is the first # template argument. False negative with less-than comparison is # avoided because those operators are usually followed by a space. # # function // bracket + no space = false positive # value < double(42) // bracket + space = true positive matched_new_or_template = match.group(1) # Avoid arrays by looking for brackets that come after the closing # parenthesis. if Match(r'\([^()]+\)\s*\[', match.group(3)): return # Other things to ignore: # - Function pointers # - Casts to pointer types # - Placement new # - Alias declarations matched_funcptr = match.group(3) if (matched_new_or_template is None and not (matched_funcptr and (Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', matched_funcptr) or matched_funcptr.startswith('(*)'))) and not Match(r'\s*using\s+\S+\s*=\s*' + matched_type, line) and not Search(r'new\(\S+\)\s*' + matched_type, line)): error(filename, linenum, 'readability/casting', 4, 'Using deprecated casting style. ' 'Use static_cast<%s>(...) instead' % matched_type) if not expecting_function: CheckCStyleCast(filename, clean_lines, linenum, 'static_cast', r'\((int|float|double|bool|char|u?int(16|32|64))\)', error) # This doesn't catch all cases. Consider (const char * const)"hello". # # (char *) "foo" should always be a const_cast (reinterpret_cast won't # compile). if CheckCStyleCast(filename, clean_lines, linenum, 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error): pass else: # Check pointer casts for other than string constants CheckCStyleCast(filename, clean_lines, linenum, 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error) # In addition, we look for people taking the address of a cast. This # is dangerous -- casts can assign to temporaries, so the pointer doesn't # point where you think. # # Some non-identifier character is required before the '&' for the # expression to be recognized as a cast. These are casts: # expression = &static_cast(temporary()); # function(&(int*)(temporary())); # # This is not a cast: # reference_type&(int* function_param); match = Search( r'(?:[^\w]&\(([^)*][^)]*)\)[\w(])|' r'(?:[^\w]&(static|dynamic|down|reinterpret)_cast\b)', line) if match: # Try a better error message when the & is bound to something # dereferenced by the casted pointer, as opposed to the casted # pointer itself. parenthesis_error = False match = Match(r'^(.*&(?:static|dynamic|down|reinterpret)_cast\b)<', line) if match: _, y1, x1 = CloseExpression(clean_lines, linenum, len(match.group(1))) if x1 >= 0 and clean_lines.elided[y1][x1] == '(': _, y2, x2 = CloseExpression(clean_lines, y1, x1) if x2 >= 0: extended_line = clean_lines.elided[y2][x2:] if y2 < clean_lines.NumLines() - 1: extended_line += clean_lines.elided[y2 + 1] if Match(r'\s*(?:->|\[)', extended_line): parenthesis_error = True if parenthesis_error: error(filename, linenum, 'readability/casting', 4, ('Are you taking an address of something dereferenced ' 'from a cast? Wrapping the dereferenced expression in ' 'parentheses will make the binding more obvious')) else: error(filename, linenum, 'runtime/casting', 4, ('Are you taking an address of a cast? ' 'This is dangerous: could be a temp var. ' 'Take the address before doing the cast, rather than after')) def CheckCStyleCast(filename, clean_lines, linenum, cast_type, pattern, error): """Checks for a C-style cast by looking for the pattern. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. cast_type: The string for the C++ cast to recommend. This is either reinterpret_cast, static_cast, or const_cast, depending. pattern: The regular expression used to find C-style casts. error: The function to call with any errors found. Returns: True if an error was emitted. False otherwise. """ line = clean_lines.elided[linenum] match = Search(pattern, line) if not match: return False # Exclude lines with keywords that tend to look like casts context = line[0:match.start(1) - 1] if Match(r'.*\b(?:sizeof|alignof|alignas|[_A-Z][_A-Z0-9]*)\s*$', context): return False # Try expanding current context to see if we one level of # parentheses inside a macro. if linenum > 0: for i in xrange(linenum - 1, max(0, linenum - 5), -1): context = clean_lines.elided[i] + context if Match(r'.*\b[_A-Z][_A-Z0-9]*\s*\((?:\([^()]*\)|[^()])*$', context): return False # operator++(int) and operator--(int) if context.endswith(' operator++') or context.endswith(' operator--'): return False # A single unnamed argument for a function tends to look like old style cast. # If we see those, don't issue warnings for deprecated casts. remainder = line[match.end(0):] if Match(r'^\s*(?:;|const\b|throw\b|final\b|override\b|[=>{),]|->)', remainder): return False # At this point, all that should be left is actual casts. error(filename, linenum, 'readability/casting', 4, 'Using C-style cast. Use %s<%s>(...) instead' % (cast_type, match.group(1))) return True def ExpectingFunctionArgs(clean_lines, linenum): """Checks whether where function type arguments are expected. Args: clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. Returns: True if the line at 'linenum' is inside something that expects arguments of function types. """ line = clean_lines.elided[linenum] return (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or (linenum >= 2 and (Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\((?:\S+,)?\s*$', clean_lines.elided[linenum - 1]) or Match(r'^\s*MOCK_(?:CONST_)?METHOD\d+(?:_T)?\(\s*$', clean_lines.elided[linenum - 2]) or Search(r'\bstd::m?function\s*\<\s*$', clean_lines.elided[linenum - 1])))) _HEADERS_CONTAINING_TEMPLATES = ( ('', ('deque',)), ('', ('unary_function', 'binary_function', 'plus', 'minus', 'multiplies', 'divides', 'modulus', 'negate', 'equal_to', 'not_equal_to', 'greater', 'less', 'greater_equal', 'less_equal', 'logical_and', 'logical_or', 'logical_not', 'unary_negate', 'not1', 'binary_negate', 'not2', 'bind1st', 'bind2nd', 'pointer_to_unary_function', 'pointer_to_binary_function', 'ptr_fun', 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t', 'mem_fun_ref_t', 'const_mem_fun_t', 'const_mem_fun1_t', 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t', 'mem_fun_ref', )), ('', ('numeric_limits',)), ('', ('list',)), ('', ('multimap',)), ('', ('allocator', 'make_shared', 'make_unique', 'shared_ptr', 'unique_ptr', 'weak_ptr')), ('', ('queue', 'priority_queue',)), ('', ('multiset',)), ('', ('stack',)), ('', ('char_traits', 'basic_string',)), ('', ('tuple',)), ('', ('unordered_map', 'unordered_multimap')), ('', ('unordered_set', 'unordered_multiset')), ('', ('pair',)), ('', ('vector',)), # gcc extensions. # Note: std::hash is their hash, ::hash is our hash ('', ('hash_map', 'hash_multimap',)), ('', ('hash_set', 'hash_multiset',)), ('', ('slist',)), ) _HEADERS_MAYBE_TEMPLATES = ( ('', ('copy', 'max', 'min', 'min_element', 'sort', 'transform', )), ('', ('forward', 'make_pair', 'move', 'swap')), ) _RE_PATTERN_STRING = re.compile(r'\bstring\b') _re_pattern_headers_maybe_templates = [] for _header, _templates in _HEADERS_MAYBE_TEMPLATES: for _template in _templates: # Match max(..., ...), max(..., ...), but not foo->max, foo.max or # 'type::max()'. _re_pattern_headers_maybe_templates.append( (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), _template, _header)) # Match set, but not foo->set, foo.set _re_pattern_headers_maybe_templates.append( (re.compile(r'[^>.]\bset\s*\<'), 'set<>', '')) # Match 'map var' and 'std::map(...)', but not 'map(...)'' _re_pattern_headers_maybe_templates.append( (re.compile(r'(std\b::\bmap\s*\<)|(^(std\b::\b)map\b\(\s*\<)'), 'map<>', '')) # Other scripts may reach in and modify this pattern. _re_pattern_templates = [] for _header, _templates in _HEADERS_CONTAINING_TEMPLATES: for _template in _templates: _re_pattern_templates.append( (re.compile(r'(\<|\b)' + _template + r'\s*\<'), _template + '<>', _header)) def FilesBelongToSameModule(filename_cc, filename_h): """Check if these two filenames belong to the same module. The concept of a 'module' here is a as follows: foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the same 'module' if they are in the same directory. some/path/public/xyzzy and some/path/internal/xyzzy are also considered to belong to the same module here. If the filename_cc contains a longer path than the filename_h, for example, '/absolute/path/to/base/sysinfo.cc', and this file would include 'base/sysinfo.h', this function also produces the prefix needed to open the header. This is used by the caller of this function to more robustly open the header file. We don't have access to the real include paths in this context, so we need this guesswork here. Known bugs: tools/base/bar.cc and base/bar.h belong to the same module according to this implementation. Because of this, this function gives some false positives. This should be sufficiently rare in practice. Args: filename_cc: is the path for the source (e.g. .cc) file filename_h: is the path for the header path Returns: Tuple with a bool and a string: bool: True if filename_cc and filename_h belong to the same module. string: the additional prefix needed to open the header file. """ fileinfo_cc = FileInfo(filename_cc) if not fileinfo_cc.Extension().lstrip('.') in GetNonHeaderExtensions(): return (False, '') fileinfo_h = FileInfo(filename_h) if not IsHeaderExtension(fileinfo_h.Extension().lstrip('.')): return (False, '') filename_cc = filename_cc[:-(len(fileinfo_cc.Extension()))] matched_test_suffix = Search(_TEST_FILE_SUFFIX, fileinfo_cc.BaseName()) if matched_test_suffix: filename_cc = filename_cc[:-len(matched_test_suffix.group(1))] filename_cc = filename_cc.replace('/public/', '/') filename_cc = filename_cc.replace('/internal/', '/') filename_h = filename_h[:-(len(fileinfo_h.Extension()))] if filename_h.endswith('-inl'): filename_h = filename_h[:-len('-inl')] filename_h = filename_h.replace('/public/', '/') filename_h = filename_h.replace('/internal/', '/') files_belong_to_same_module = filename_cc.endswith(filename_h) common_path = '' if files_belong_to_same_module: common_path = filename_cc[:-len(filename_h)] return files_belong_to_same_module, common_path def UpdateIncludeState(filename, include_dict, io=codecs): """Fill up the include_dict with new includes found from the file. Args: filename: the name of the header to read. include_dict: a dictionary in which the headers are inserted. io: The io factory to use to read the file. Provided for testability. Returns: True if a header was successfully added. False otherwise. """ headerfile = None try: with io.open(filename, 'r', 'utf8', 'replace') as headerfile: linenum = 0 for line in headerfile: linenum += 1 clean_line = CleanseComments(line) match = _RE_PATTERN_INCLUDE.search(clean_line) if match: include = match.group(2) include_dict.setdefault(include, linenum) return True except IOError: return False def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs): """Reports for missing stl includes. This function will output warnings to make sure you are including the headers necessary for the stl containers and functions that you use. We only give one reason to include a header. For example, if you use both equal_to<> and less<> in a .h file, only one (the latter in the file) of these will be reported as a reason to include the . Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. include_state: An _IncludeState instance. error: The function to call with any errors found. io: The IO factory to use to read the header file. Provided for unittest injection. """ required = {} # A map of header name to linenumber and the template entity. # Example of required: { '': (1219, 'less<>') } for linenum in xrange(clean_lines.NumLines()): line = clean_lines.elided[linenum] if not line or line[0] == '#': continue # String is special -- it is a non-templatized type in STL. matched = _RE_PATTERN_STRING.search(line) if matched: # Don't warn about strings in non-STL namespaces: # (We check only the first match per line; good enough.) prefix = line[:matched.start()] if prefix.endswith('std::') or not prefix.endswith('::'): required[''] = (linenum, 'string') for pattern, template, header in _re_pattern_headers_maybe_templates: if pattern.search(line): required[header] = (linenum, template) # The following function is just a speed up, no semantics are changed. if not '<' in line: # Reduces the cpu time usage by skipping lines. continue for pattern, template, header in _re_pattern_templates: matched = pattern.search(line) if matched: # Don't warn about IWYU in non-STL namespaces: # (We check only the first match per line; good enough.) prefix = line[:matched.start()] if prefix.endswith('std::') or not prefix.endswith('::'): required[header] = (linenum, template) # The policy is that if you #include something in foo.h you don't need to # include it again in foo.cc. Here, we will look at possible includes. # Let's flatten the include_state include_list and copy it into a dictionary. include_dict = dict([item for sublist in include_state.include_list for item in sublist]) # Did we find the header for this file (if any) and successfully load it? header_found = False # Use the absolute path so that matching works properly. abs_filename = FileInfo(filename).FullName() # For Emacs's flymake. # If cpplint is invoked from Emacs's flymake, a temporary file is generated # by flymake and that file name might end with '_flymake.cc'. In that case, # restore original file name here so that the corresponding header file can be # found. # e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h' # instead of 'foo_flymake.h' abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename) # include_dict is modified during iteration, so we iterate over a copy of # the keys. header_keys = list(include_dict.keys()) for header in header_keys: (same_module, common_path) = FilesBelongToSameModule(abs_filename, header) fullpath = common_path + header if same_module and UpdateIncludeState(fullpath, include_dict, io): header_found = True # If we can't find the header file for a .cc, assume it's because we don't # know where to look. In that case we'll give up as we're not sure they # didn't include it in the .h file. # TODO(unknown): Do a better job of finding .h files so we are confident that # not having the .h file means there isn't one. if not header_found: for extension in GetNonHeaderExtensions(): if filename.endswith('.' + extension): return # All the lines have been processed, report the errors found. for required_header_unstripped in sorted(required, key=required.__getitem__): template = required[required_header_unstripped][1] if required_header_unstripped.strip('<>"') not in include_dict: error(filename, required[required_header_unstripped][0], 'build/include_what_you_use', 4, 'Add #include ' + required_header_unstripped + ' for ' + template) _RE_PATTERN_EXPLICIT_MAKEPAIR = re.compile(r'\bmake_pair\s*<') def CheckMakePairUsesDeduction(filename, clean_lines, linenum, error): """Check that make_pair's template arguments are deduced. G++ 4.6 in C++11 mode fails badly if make_pair's template arguments are specified explicitly, and such use isn't intended in any case. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] match = _RE_PATTERN_EXPLICIT_MAKEPAIR.search(line) if match: error(filename, linenum, 'build/explicit_make_pair', 4, # 4 = high confidence 'For C++11-compatibility, omit template arguments from make_pair' ' OR use pair directly OR if appropriate, construct a pair directly') def CheckRedundantVirtual(filename, clean_lines, linenum, error): """Check if line contains a redundant "virtual" function-specifier. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ # Look for "virtual" on current line. line = clean_lines.elided[linenum] virtual = Match(r'^(.*)(\bvirtual\b)(.*)$', line) if not virtual: return # Ignore "virtual" keywords that are near access-specifiers. These # are only used in class base-specifier and do not apply to member # functions. if (Search(r'\b(public|protected|private)\s+$', virtual.group(1)) or Match(r'^\s+(public|protected|private)\b', virtual.group(3))): return # Ignore the "virtual" keyword from virtual base classes. Usually # there is a column on the same line in these cases (virtual base # classes are rare in google3 because multiple inheritance is rare). if Match(r'^.*[^:]:[^:].*$', line): return # Look for the next opening parenthesis. This is the start of the # parameter list (possibly on the next line shortly after virtual). # TODO(unknown): doesn't work if there are virtual functions with # decltype() or other things that use parentheses, but csearch suggests # that this is rare. end_col = -1 end_line = -1 start_col = len(virtual.group(2)) for start_line in xrange(linenum, min(linenum + 3, clean_lines.NumLines())): line = clean_lines.elided[start_line][start_col:] parameter_list = Match(r'^([^(]*)\(', line) if parameter_list: # Match parentheses to find the end of the parameter list (_, end_line, end_col) = CloseExpression( clean_lines, start_line, start_col + len(parameter_list.group(1))) break start_col = 0 if end_col < 0: return # Couldn't find end of parameter list, give up # Look for "override" or "final" after the parameter list # (possibly on the next few lines). for i in xrange(end_line, min(end_line + 3, clean_lines.NumLines())): line = clean_lines.elided[i][end_col:] match = Search(r'\b(override|final)\b', line) if match: error(filename, linenum, 'readability/inheritance', 4, ('"virtual" is redundant since function is ' 'already declared as "%s"' % match.group(1))) # Set end_col to check whole lines after we are done with the # first line. end_col = 0 if Search(r'[^\w]\s*$', line): break def CheckRedundantOverrideOrFinal(filename, clean_lines, linenum, error): """Check if line contains a redundant "override" or "final" virt-specifier. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ # Look for closing parenthesis nearby. We need one to confirm where # the declarator ends and where the virt-specifier starts to avoid # false positives. line = clean_lines.elided[linenum] declarator_end = line.rfind(')') if declarator_end >= 0: fragment = line[declarator_end:] else: if linenum > 1 and clean_lines.elided[linenum - 1].rfind(')') >= 0: fragment = line else: return # Check that at most one of "override" or "final" is present, not both if Search(r'\boverride\b', fragment) and Search(r'\bfinal\b', fragment): error(filename, linenum, 'readability/inheritance', 4, ('"override" is redundant since function is ' 'already declared as "final"')) # Returns true if we are at a new block, and it is directly # inside of a namespace. def IsBlockInNameSpace(nesting_state, is_forward_declaration): """Checks that the new block is directly in a namespace. Args: nesting_state: The _NestingState object that contains info about our state. is_forward_declaration: If the class is a forward declared class. Returns: Whether or not the new block is directly in a namespace. """ if is_forward_declaration: return len(nesting_state.stack) >= 1 and ( isinstance(nesting_state.stack[-1], _NamespaceInfo)) return (len(nesting_state.stack) > 1 and nesting_state.stack[-1].check_namespace_indentation and isinstance(nesting_state.stack[-2], _NamespaceInfo)) def ShouldCheckNamespaceIndentation(nesting_state, is_namespace_indent_item, raw_lines_no_comments, linenum): """This method determines if we should apply our namespace indentation check. Args: nesting_state: The current nesting state. is_namespace_indent_item: If we just put a new class on the stack, True. If the top of the stack is not a class, or we did not recently add the class, False. raw_lines_no_comments: The lines without the comments. linenum: The current line number we are processing. Returns: True if we should apply our namespace indentation check. Currently, it only works for classes and namespaces inside of a namespace. """ is_forward_declaration = IsForwardClassDeclaration(raw_lines_no_comments, linenum) if not (is_namespace_indent_item or is_forward_declaration): return False # If we are in a macro, we do not want to check the namespace indentation. if IsMacroDefinition(raw_lines_no_comments, linenum): return False return IsBlockInNameSpace(nesting_state, is_forward_declaration) # Call this method if the line is directly inside of a namespace. # If the line above is blank (excluding comments) or the start of # an inner namespace, it cannot be indented. def CheckItemIndentationInNamespace(filename, raw_lines_no_comments, linenum, error): line = raw_lines_no_comments[linenum] if Match(r'^\s+', line): error(filename, linenum, 'runtime/indentation_namespace', 4, 'Do not indent within a namespace') def ProcessLine(filename, file_extension, clean_lines, line, include_state, function_state, nesting_state, error, extra_check_functions=None): """Processes a single line in the file. Args: filename: Filename of the file that is being processed. file_extension: The extension (dot not included) of the file. clean_lines: An array of strings, each representing a line of the file, with comments stripped. line: Number of line being processed. include_state: An _IncludeState instance in which the headers are inserted. function_state: A _FunctionState instance which counts function lines, etc. nesting_state: A NestingState instance which maintains information about the current stack of nested blocks being parsed. error: A callable to which errors are reported, which takes 4 arguments: filename, line number, error level, and message extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ raw_lines = clean_lines.raw_lines ParseNolintSuppressions(filename, raw_lines[line], line, error) nesting_state.Update(filename, clean_lines, line, error) CheckForNamespaceIndentation(filename, nesting_state, clean_lines, line, error) if nesting_state.InAsmBlock(): return CheckForFunctionLengths(filename, clean_lines, line, function_state, error) CheckForMultilineCommentsAndStrings(filename, clean_lines, line, error) CheckStyle(filename, clean_lines, line, file_extension, nesting_state, error) CheckLanguage(filename, clean_lines, line, file_extension, include_state, nesting_state, error) CheckForNonConstReference(filename, clean_lines, line, nesting_state, error) CheckForNonStandardConstructs(filename, clean_lines, line, nesting_state, error) CheckVlogArguments(filename, clean_lines, line, error) CheckPosixThreading(filename, clean_lines, line, error) CheckInvalidIncrement(filename, clean_lines, line, error) CheckMakePairUsesDeduction(filename, clean_lines, line, error) CheckRedundantVirtual(filename, clean_lines, line, error) CheckRedundantOverrideOrFinal(filename, clean_lines, line, error) if extra_check_functions: for check_fn in extra_check_functions: check_fn(filename, clean_lines, line, error) def FlagCxx11Features(filename, clean_lines, linenum, error): """Flag those c++11 features that we only allow in certain places. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) # Flag unapproved C++ TR1 headers. if include and include.group(1).startswith('tr1/'): error(filename, linenum, 'build/c++tr1', 5, ('C++ TR1 headers such as <%s> are unapproved.') % include.group(1)) # Flag unapproved C++11 headers. if include and include.group(1) in ('cfenv', 'condition_variable', 'fenv.h', 'future', 'mutex', 'thread', 'chrono', 'ratio', 'regex', 'system_error', ): error(filename, linenum, 'build/c++11', 5, ('<%s> is an unapproved C++11 header.') % include.group(1)) # The only place where we need to worry about C++11 keywords and library # features in preprocessor directives is in macro definitions. if Match(r'\s*#', line) and not Match(r'\s*#\s*define\b', line): return # These are classes and free functions. The classes are always # mentioned as std::*, but we only catch the free functions if # they're not found by ADL. They're alphabetical by header. for top_name in ( # type_traits 'alignment_of', 'aligned_union', ): if Search(r'\bstd::%s\b' % top_name, line): error(filename, linenum, 'build/c++11', 5, ('std::%s is an unapproved C++11 class or function. Send c-style ' 'an example of where it would make your code more readable, and ' 'they may let you use it.') % top_name) def FlagCxx14Features(filename, clean_lines, linenum, error): """Flag those C++14 features that we restrict. Args: filename: The name of the current file. clean_lines: A CleansedLines instance containing the file. linenum: The number of the line to check. error: The function to call with any errors found. """ line = clean_lines.elided[linenum] include = Match(r'\s*#\s*include\s+[<"]([^<"]+)[">]', line) # Flag unapproved C++14 headers. if include and include.group(1) in ('scoped_allocator', 'shared_mutex'): error(filename, linenum, 'build/c++14', 5, ('<%s> is an unapproved C++14 header.') % include.group(1)) def ProcessFileData(filename, file_extension, lines, error, extra_check_functions=None): """Performs lint checks and reports any errors to the given error function. Args: filename: Filename of the file that is being processed. file_extension: The extension (dot not included) of the file. lines: An array of strings, each representing a line of the file, with the last element being empty if the file is terminated with a newline. error: A callable to which errors are reported, which takes 4 arguments: filename, line number, error level, and message extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ lines = (['// marker so line numbers and indices both start at 1'] + lines + ['// marker so line numbers end in a known way']) include_state = _IncludeState() function_state = _FunctionState() nesting_state = NestingState() ResetNolintSuppressions() CheckForCopyright(filename, lines, error) ProcessGlobalSuppresions(lines) RemoveMultiLineComments(filename, lines, error) clean_lines = CleansedLines(lines) if IsHeaderExtension(file_extension): CheckForHeaderGuard(filename, clean_lines, error) for line in xrange(clean_lines.NumLines()): ProcessLine(filename, file_extension, clean_lines, line, include_state, function_state, nesting_state, error, extra_check_functions) FlagCxx11Features(filename, clean_lines, line, error) nesting_state.CheckCompletedBlocks(filename, error) CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) # Check that the .cc file has included its header if it exists. if _IsSourceExtension(file_extension): CheckHeaderFileIncluded(filename, include_state, error) # We check here rather than inside ProcessLine so that we see raw # lines rather than "cleaned" lines. CheckForBadCharacters(filename, lines, error) CheckForNewlineAtEOF(filename, lines, error) def ProcessConfigOverrides(filename): """ Loads the configuration files and processes the config overrides. Args: filename: The name of the file being processed by the linter. Returns: False if the current |filename| should not be processed further. """ abs_filename = os.path.abspath(filename) cfg_filters = [] keep_looking = True while keep_looking: abs_path, base_name = os.path.split(abs_filename) if not base_name: break # Reached the root directory. cfg_file = os.path.join(abs_path, "CPPLINT.cfg") abs_filename = abs_path if not os.path.isfile(cfg_file): continue try: with open(cfg_file) as file_handle: for line in file_handle: line, _, _ = line.partition('#') # Remove comments. if not line.strip(): continue name, _, val = line.partition('=') name = name.strip() val = val.strip() if name == 'set noparent': keep_looking = False elif name == 'filter': cfg_filters.append(val) elif name == 'exclude_files': # When matching exclude_files pattern, use the base_name of # the current file name or the directory name we are processing. # For example, if we are checking for lint errors in /foo/bar/baz.cc # and we found the .cfg file at /foo/CPPLINT.cfg, then the config # file's "exclude_files" filter is meant to be checked against "bar" # and not "baz" nor "bar/baz.cc". if base_name: pattern = re.compile(val) if pattern.match(base_name): if _cpplint_state.quiet: # Suppress "Ignoring file" warning when using --quiet. return False _cpplint_state.PrintInfo('Ignoring "%s": file excluded by "%s". ' 'File path component "%s" matches ' 'pattern "%s"\n' % (filename, cfg_file, base_name, val)) return False elif name == 'linelength': global _line_length try: _line_length = int(val) except ValueError: _cpplint_state.PrintError('Line length must be numeric.') elif name == 'extensions': ProcessExtensionsOption(val) elif name == 'root': global _root # root directories are specified relative to CPPLINT.cfg dir. _root = os.path.join(os.path.dirname(cfg_file), val) elif name == 'headers': ProcessHppHeadersOption(val) elif name == 'includeorder': ProcessIncludeOrderOption(val) else: _cpplint_state.PrintError( 'Invalid configuration option (%s) in file %s\n' % (name, cfg_file)) except IOError: _cpplint_state.PrintError( "Skipping config file '%s': Can't open for reading\n" % cfg_file) keep_looking = False # Apply all the accumulated filters in reverse order (top-level directory # config options having the least priority). for cfg_filter in reversed(cfg_filters): _AddFilters(cfg_filter) return True def ProcessFile(filename, vlevel, extra_check_functions=None): """Does google-lint on a single file. Args: filename: The name of the file to parse. vlevel: The level of errors to report. Every error of confidence >= verbose_level will be reported. 0 is a good default. extra_check_functions: An array of additional check functions that will be run on each source line. Each function takes 4 arguments: filename, clean_lines, line, error """ _SetVerboseLevel(vlevel) _BackupFilters() old_errors = _cpplint_state.error_count if not ProcessConfigOverrides(filename): _RestoreFilters() return lf_lines = [] crlf_lines = [] try: # Support the UNIX convention of using "-" for stdin. Note that # we are not opening the file with universal newline support # (which codecs doesn't support anyway), so the resulting lines do # contain trailing '\r' characters if we are reading a file that # has CRLF endings. # If after the split a trailing '\r' is present, it is removed # below. if filename == '-': lines = codecs.StreamReaderWriter(sys.stdin, codecs.getreader('utf8'), codecs.getwriter('utf8'), 'replace').read().split('\n') else: with codecs.open(filename, 'r', 'utf8', 'replace') as target_file: lines = target_file.read().split('\n') # Remove trailing '\r'. # The -1 accounts for the extra trailing blank line we get from split() for linenum in range(len(lines) - 1): if lines[linenum].endswith('\r'): lines[linenum] = lines[linenum].rstrip('\r') crlf_lines.append(linenum + 1) else: lf_lines.append(linenum + 1) except IOError: _cpplint_state.PrintError( "Skipping input '%s': Can't open for reading\n" % filename) _RestoreFilters() return # Note, if no dot is found, this will give the entire filename as the ext. file_extension = filename[filename.rfind('.') + 1:] # When reading from stdin, the extension is unknown, so no cpplint tests # should rely on the extension. if filename != '-' and file_extension not in GetAllExtensions(): pass # Ignition: never print this # _cpplint_state.PrintError('Ignoring %s; not a valid file name ' # '(%s)\n' % (filename, ', '.join(GetAllExtensions()))) else: ProcessFileData(filename, file_extension, lines, Error, extra_check_functions) # If end-of-line sequences are a mix of LF and CR-LF, issue # warnings on the lines with CR. # # Don't issue any warnings if all lines are uniformly LF or CR-LF, # since critique can handle these just fine, and the style guide # doesn't dictate a particular end of line sequence. # # We can't depend on os.linesep to determine what the desired # end-of-line sequence should be, since that will return the # server-side end-of-line sequence. if lf_lines and crlf_lines: # Warn on every line with CR. An alternative approach might be to # check whether the file is mostly CRLF or just LF, and warn on the # minority, we bias toward LF here since most tools prefer LF. for linenum in crlf_lines: Error(filename, linenum, 'whitespace/newline', 1, 'Unexpected \\r (^M) found; better to use only \\n') # Suppress printing anything if --quiet was passed unless the error # count has increased after processing this file. if not _cpplint_state.quiet or old_errors != _cpplint_state.error_count: pass # Ignition: never print "Done Processing" # _cpplint_state.PrintInfo('Done processing %s\n' % filename) _RestoreFilters() def PrintUsage(message): """Prints a brief usage string and exits, optionally with an error message. Args: message: The optional error message. """ sys.stderr.write(_USAGE % (list(GetAllExtensions()), ','.join(list(GetAllExtensions())), GetHeaderExtensions(), ','.join(GetHeaderExtensions()))) if message: sys.exit('\nFATAL ERROR: ' + message) else: sys.exit(0) def PrintVersion(): sys.stdout.write('Cpplint fork (https://github.com/cpplint/cpplint)\n') sys.stdout.write('cpplint ' + __VERSION__ + '\n') sys.stdout.write('Python ' + sys.version + '\n') sys.exit(0) def PrintCategories(): """Prints a list of all the error-categories used by error messages. These are the categories used to filter messages via --filter. """ sys.stderr.write(''.join(' %s\n' % cat for cat in _ERROR_CATEGORIES)) sys.exit(0) def ParseArguments(args): """Parses the command line arguments. This may set the output format and verbosity level as side-effects. Args: args: The command line arguments: Returns: The list of filenames to lint. """ try: (opts, filenames) = getopt.getopt(args, '', ['help', 'output=', 'verbose=', 'v=', 'version', 'counting=', 'filter=', 'root=', 'repository=', 'linelength=', 'extensions=', 'exclude=', 'recursive', 'headers=', 'includeorder=', 'quiet']) except getopt.GetoptError: PrintUsage('Invalid arguments.') verbosity = _VerboseLevel() output_format = _OutputFormat() filters = '' quiet = _Quiet() counting_style = '' recursive = False for (opt, val) in opts: if opt == '--help': PrintUsage(None) if opt == '--version': PrintVersion() elif opt == '--output': if val not in ('emacs', 'vs7', 'eclipse', 'junit', 'sed', 'gsed'): PrintUsage('The only allowed output formats are emacs, vs7, eclipse ' 'sed, gsed and junit.') output_format = val elif opt == '--quiet': quiet = True elif opt == '--verbose' or opt == '--v': verbosity = int(val) elif opt == '--filter': filters = val if not filters: PrintCategories() elif opt == '--counting': if val not in ('total', 'toplevel', 'detailed'): PrintUsage('Valid counting options are total, toplevel, and detailed') counting_style = val elif opt == '--root': global _root _root = val elif opt == '--repository': global _repository _repository = val elif opt == '--linelength': global _line_length try: _line_length = int(val) except ValueError: PrintUsage('Line length must be digits.') elif opt == '--exclude': global _excludes if not _excludes: _excludes = set() _excludes.update(glob.glob(val)) elif opt == '--extensions': ProcessExtensionsOption(val) elif opt == '--headers': ProcessHppHeadersOption(val) elif opt == '--recursive': recursive = True elif opt == '--includeorder': ProcessIncludeOrderOption(val) if not filenames: PrintUsage('No files were specified.') if recursive: filenames = _ExpandDirectories(filenames) if _excludes: filenames = _FilterExcludedFiles(filenames) _SetOutputFormat(output_format) _SetQuiet(quiet) _SetVerboseLevel(verbosity) _SetFilters(filters) _SetCountingStyle(counting_style) filenames.sort() return filenames def _ExpandDirectories(filenames): """Searches a list of filenames and replaces directories in the list with all files descending from those directories. Files with extensions not in the valid extensions list are excluded. Args: filenames: A list of files or directories Returns: A list of all files that are members of filenames or descended from a directory in filenames """ expanded = set() for filename in filenames: if not os.path.isdir(filename): expanded.add(filename) continue for root, _, files in os.walk(filename): for loopfile in files: fullname = os.path.join(root, loopfile) if fullname.startswith('.' + os.path.sep): fullname = fullname[len('.' + os.path.sep):] expanded.add(fullname) filtered = [] for filename in expanded: if os.path.splitext(filename)[1][1:] in GetAllExtensions(): filtered.append(filename) return filtered def _FilterExcludedFiles(fnames): """Filters out files listed in the --exclude command line switch. File paths in the switch are evaluated relative to the current working directory """ exclude_paths = [os.path.abspath(f) for f in _excludes] # because globbing does not work recursively, exclude all subpath of all excluded entries return [f for f in fnames if not any(e for e in exclude_paths if _IsParentOrSame(e, os.path.abspath(f)))] def _IsParentOrSame(parent, child): """Return true if child is subdirectory of parent. Assumes both paths are absolute and don't contain symlinks. """ parent = os.path.normpath(parent) child = os.path.normpath(child) if parent == child: return True prefix = os.path.commonprefix([parent, child]) if prefix != parent: return False # Note: os.path.commonprefix operates on character basis, so # take extra care of situations like '/foo/ba' and '/foo/bar/baz' child_suffix = child[len(prefix):] child_suffix = child_suffix.lstrip(os.sep) return child == os.path.join(prefix, child_suffix) def main(): filenames = ParseArguments(sys.argv[1:]) backup_err = sys.stderr try: # Change stderr to write with replacement characters so we don't die # if we try to print something containing non-ASCII characters. sys.stderr = codecs.StreamReader(sys.stderr, 'replace') _cpplint_state.ResetErrorCounts() for filename in filenames: ProcessFile(filename, _cpplint_state.verbose_level) # If --quiet is passed, suppress printing error count unless there are errors. if not _cpplint_state.quiet or _cpplint_state.error_count > 0: _cpplint_state.PrintErrorCounts() if _cpplint_state.output_format == 'junit': sys.stderr.write(_cpplint_state.FormatJUnitXML()) finally: sys.stderr = backup_err sys.exit(_cpplint_state.error_count > 0) if __name__ == '__main__': main() ign-cmake-ignition-cmake2_2.10.0/CMakeLists.txt0000664000175000017500000001653414160533245021165 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) #============================================================================ # Initialize the project #============================================================================ project(ignition-cmake2 VERSION 2.10.0) #-------------------------------------- # Initialize the IGNITION_CMAKE_DIR variable with the location of the cmake # directory that sits next to this find-module. set(IGNITION_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake") #-------------------------------------- # Add the location of this package's cmake directory to the CMAKE_MODULE_PATH list(APPEND CMAKE_MODULE_PATH "${IGNITION_CMAKE_DIR}") #-------------------------------------- # include the master IgnCMake module include(IgnCMake) #-------------------------------------- # Set up the project ign_configure_project(VERSION_SUFFIX) #-------------------------------------- # Set project-specific options option(BUILDSYSTEM_TESTING "Enable extended buildsystem testing" FALSE) #-------------------------------------- # Install the ignition documentation files # Note: This is not actually creating a doc target for ign-cmake; this is just # installing files that are useful for generating the documentation of other # ignition projects. add_subdirectory(doc) #-------------------------------------- # Install the benchmark files install(DIRECTORY benchmark/ DESTINATION ${IGN_DATA_INSTALL_DIR}/benchmark) #-------------------------------------- # Install the codecheck files install(DIRECTORY codecheck/ DESTINATION ${IGN_DATA_INSTALL_DIR}/codecheck) #-------------------------------------- # Install the tools files install(DIRECTORY tools/ DESTINATION ${IGN_DATA_INSTALL_DIR}/tools) #============================================================================ # Configure the package to be installed #============================================================================ #-------------------------------------- # Create configuration and installation variables set(ign_config_input "${CMAKE_CURRENT_SOURCE_DIR}/config/ignition-cmake-config.cmake.in") set(ign_config_output "${PROJECT_NAME_LOWER}-config.cmake") set(ign_version_output "${PROJECT_NAME_LOWER}-config-version.cmake") set(ign_config_install_dir "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME_LOWER}") set(ign_pkgconfig_input "${CMAKE_CURRENT_SOURCE_DIR}/config/ignition-cmake.pc.in") set(ign_pkgconfig_output "${CMAKE_BINARY_DIR}/ignition-cmake${PROJECT_VERSION_MAJOR}.pc") set(ign_pkgconfig_install_dir "${IGN_LIB_INSTALL_DIR}/pkgconfig") set(ign_utilities_target ${PROJECT_EXPORT_NAME}-utilities) set(ign_utilities_import_target_name ${PROJECT_EXPORT_NAME}::${ign_utilities_target}) set(ign_utilities_target_output_filename "${ign_utilities_target}-targets.cmake") set(simple_utilities_import_name ${PROJECT_EXPORT_NAME}::utilities) #-------------------------------------- # Configure and install the config file configure_package_config_file( ${ign_config_input} ${ign_config_output} INSTALL_DESTINATION ${ign_config_install_dir} PATH_VARS IGN_DATA_INSTALL_DIR NO_CHECK_REQUIRED_COMPONENTS_MACRO) #-------------------------------------- # Configure and install the version file write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output} VERSION "${PROJECT_VERSION_FULL_NO_SUFFIX}" COMPATIBILITY SameMajorVersion) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${ign_config_output} ${CMAKE_CURRENT_BINARY_DIR}/${ign_version_output} DESTINATION ${ign_config_install_dir} COMPONENT cmake) #-------------------------------------- # Configure and install the pkgconfig file (needed for utilities headers) file(RELATIVE_PATH IGN_PC_CONFIG_RELATIVE_PATH_TO_PREFIX "${CMAKE_INSTALL_PREFIX}/${ign_pkgconfig_install_dir}" "${CMAKE_INSTALL_PREFIX}" ) configure_file(${ign_pkgconfig_input} ${ign_pkgconfig_output} @ONLY) install( FILES ${ign_pkgconfig_output} DESTINATION ${ign_pkgconfig_install_dir} COMPONENT pkgconfig) #============================================================================ # Create and install the utilities component #============================================================================ add_library(${ign_utilities_target} INTERFACE) target_include_directories(${ign_utilities_target} INTERFACE $ $ $) # Export and install the interface target install( TARGETS ${ign_utilities_target} EXPORT ${ign_utilities_target} COMPONENT interface) export( EXPORT ${ign_utilities_target} FILE ${ign_utilities_target_output_filename} NAMESPACE ${PROJECT_EXPORT_NAME}::) install( EXPORT ${ign_utilities_target} DESTINATION ${ign_config_install_dir} FILE ${ign_utilities_target_output_filename} NAMESPACE ${PROJECT_EXPORT_NAME}::) # Install the header directory # Note: The trailing slash after "include" is necessary install( DIRECTORY include/ DESTINATION ${IGN_INCLUDE_INSTALL_DIR_FULL} COMPONENT headers) #============================================================================ # Install the files for this package #============================================================================ set(ign_modules_install_dir "${ign_config_install_dir}/cmake${PROJECT_VERSION_MAJOR}") file(GLOB modules "cmake/*.cmake") file(GLOB templates "cmake/*.in") install( FILES ${modules} ${templates} DESTINATION ${ign_modules_install_dir} COMPONENT modules) file(GLOB pkgconfig_templates "cmake/pkgconfig/*.in") install( FILES ${pkgconfig_templates} DESTINATION ${ign_modules_install_dir}/pkgconfig COMPONENT modules) message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}") include(CTest) if (BUILD_TESTING) add_subdirectory(test) endif() if (BUILD_TESTING AND BUILDSYSTEM_TESTING) #============================================================================ # Build examples #============================================================================ # Do a fake install of ign-cmake in order to test the examples. # Copy or symlink the config.cmake files and cmake folder set(FAKE_BUILD_DIRECTORY "${CMAKE_BINARY_DIR}/fake/build") set(FAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/fake/install") file(MAKE_DIRECTORY ${FAKE_BUILD_DIRECTORY}) file(MAKE_DIRECTORY ${FAKE_INSTALL_PREFIX}) include(ExternalProject) ExternalProject_Add( FAKE_INSTALL SOURCE_DIR "${CMAKE_SOURCE_DIR}" # BUILD_ALWAYS needed since cmake doesn't notice when # example files change. # See alternate approach in a2113e0997c9 if this becomes too slow BUILD_ALWAYS 1 CMAKE_ARGS "-DBUILD_TESTING=OFF" "-DCMAKE_INSTALL_PREFIX=${FAKE_INSTALL_PREFIX}" ) add_subdirectory(examples) endif() # Codecheck set(CPPCHECK_DIRS ${CMAKE_SOURCE_DIR}/examples ) set(CPPCHECK_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/examples ) set(IGNITION_CMAKE_CODECHECK_DIR "${CMAKE_CURRENT_SOURCE_DIR}/codecheck") include(IgnCodeCheck) ign_setup_target_for_codecheck() # Docs set(IGNITION_CMAKE_DOXYGEN_DIR "${CMAKE_CURRENT_SOURCE_DIR}/doc/doxygen") configure_file(${CMAKE_SOURCE_DIR}/api.md.in ${CMAKE_BINARY_DIR}/api.md) configure_file(${CMAKE_SOURCE_DIR}/tutorials.md.in ${CMAKE_BINARY_DIR}/tutorials.md) ign_create_docs( API_MAINPAGE_MD "${CMAKE_BINARY_DIR}/api.md" TUTORIALS_MAINPAGE_MD "${CMAKE_BINARY_DIR}/tutorials.md" ) ign-cmake-ignition-cmake2_2.10.0/benchmark/0000775000175000017500000000000014160533245020346 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/benchmark/run_benchmarks.py0000775000175000017500000001005214160533245023722 0ustar jriverojrivero#!/usr/bin/env python3 # Copyright 2019 Open Source Robotics Foundation, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import argparse import datetime import logging import os import shutil import subprocess import sys import tarfile logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger('run_benchmarks') def run_benchmark(target, output_dir): """Run a specified benchmark target.""" basename = os.path.basename(target) name = basename.split('BENCHMARK_')[1] filename = os.path.join(output_dir, name + '.json') logger.info('Running benchmark: {name}'.format_map(locals())) cmd = [ target, '--benchmark_out={filename}'.format_map(locals()), '--benchmark_out_format=json' ] logger.debug(' '.join(cmd)) try: benchmark = subprocess.call(cmd, stdout=sys.stdout, stderr=sys.stderr) except (OSError, subprocess.CalledProcessError) as exception: logger.error('Exception occurred: ' + str(exception)) logger.error('Benchmark failed') else: logger.info('Finished benchmark: {name}'.format_map(locals())) def run_benchmarks(targets, output_dir): """Run all benchmark targets in a list.""" for target in targets: run_benchmark(target, output_dir) def create_results_dir(project_name, time, root, version_file): """Create a directory to store benchmark results in.""" time_str = time.strftime('%Y-%m-%d_%H-%M-%S') folder_name = '{project_name}_{time_str}'.format_map(locals()) results_dir = os.path.join(root, folder_name) logger.info('Creating results dir: {results_dir}'.format_map(locals())) # Create output paths as needed. if not os.path.exists(root): os.mkdir(root) if not os.path.exists(results_dir): os.mkdir(results_dir) # Copy version information over shutil.copy(version_file, os.path.join(results_dir, 'version_info.json')) return results_dir def collect_results(project_name, results_dir): """Collect results from a given execution into a tar file.""" path, basename = os.path.split(results_dir) tarname = basename + '.tar.gz' with tarfile.open(os.path.join(path, tarname), 'w:gz') as tar: tar.add(results_dir, arcname=basename) logger.info('Benchmark results collected in: ' + os.path.join(path, tarname)) if __name__ == '__main__': parser = argparse.ArgumentParser('Run and aggregate available benchmarks') parser.add_argument('--project-name', help='Name of the Ignition project') parser.add_argument('--version-file', help='Generated file containing version information') parser.add_argument('--benchmark-targets', help='Targets to be executed') parser.add_argument('--results-root', help='Root directory to store results') args = parser.parse_args() # Targets will be semicolon delimited from CMake. if not os.path.exists(args.benchmark_targets): print('Invalid Targets File: {f}'.format(f=args.benchmark_targets)) parser.exit() targets = [] with open(args.benchmark_targets, 'r') as f: for line in f.readlines(): targets.extend(line.split(';')) results_dir = create_results_dir(args.project_name, datetime.datetime.utcnow(), args.results_root, args.version_file) run_benchmarks(targets, results_dir) collect_results(args.project_name, results_dir) ign-cmake-ignition-cmake2_2.10.0/configure.bat0000664000175000017500000000105714160533245021070 0ustar jriverojrivero :: NOTE: This script is only meant to be used as part of the ignition developers' CI system :: Users and developers should build and install this library using cmake and Visual Studio :: ign-cmake has no dependencies :: Go to the directory that this file configure.bat file exists in cd /d %~dp0 :: Create a build directory and configure md build cd build cmake .. -G "NMake Makefiles" -DCMAKE_INSTALL_PREFIX="%WORKSPACE_INSTALL_DIR%" -DBUILD_TESTING:BOOL=False :: If the caller wants to build and/or install, they should do so after calling this script ign-cmake-ignition-cmake2_2.10.0/examples/0000775000175000017500000000000014160533245020232 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/junit_pass.xml.in0000664000175000017500000000052514160533245023542 0ustar jriverojrivero ign-cmake-ignition-cmake2_2.10.0/examples/prerelease/0000775000175000017500000000000014160533245022361 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/src/0000775000175000017500000000000014160533245023150 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/src/CMakeLists.txt0000664000175000017500000000004514160533245025707 0ustar jriverojrivero ign_create_core_library(INTERFACE) ign-cmake-ignition-cmake2_2.10.0/examples/prerelease/CMakeLists.txt0000664000175000017500000000033014160533245025115 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-minimal1 VERSION 1.0.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project(VERSION_SUFFIX pre1) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign-cmake-ignition-cmake2_2.10.0/examples/prerelease/test/0000775000175000017500000000000014160533245023340 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/test/CMakeLists.txt0000664000175000017500000000000014160533245026066 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/README.md0000664000175000017500000000000014160533245023626 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/include/0000775000175000017500000000000014160533245024004 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/prerelease/include/CMakeLists.txt0000664000175000017500000000000014160533245026532 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/CMakeLists.txt0000664000175000017500000001513014160533245022772 0ustar jriverojriveroinclude(ExternalProject) include(GNUInstallDirs) # test multiple build types set(build_types Release RelWithDebInfo Debug) find_program(EXAMPLE_LCOV_PATH lcov) if (NOT WIN32 AND EXAMPLE_LCOV_PATH) list(APPEND build_types Coverage) endif() set(example_directories ign_conf no_ignition_prefix prerelease core_nodep core_child core_child_private comp_deps ) if (NOT CMAKE_GENERATOR MATCHES "Visual Studio") list(APPEND example_directories use_component_depsA use_component_depsB use_component_depsC ) endif() foreach(example ${example_directories}) set(run_codecheck false) if (${example} STREQUAL "ign_conf") set(example_tarball_name ignition-minimal-0.1.0.tar.bz2) elseif (${example} STREQUAL "no_ignition_prefix") set(example_tarball_name no_ignition_prefix-0.1.0.tar.bz2) elseif (${example} STREQUAL "prerelease") set(example_tarball_name ignition-minimal-1.0.0~pre1.tar.bz2) elseif (${example} STREQUAL "core_nodep") set(example_tarball_name ignition-core_no_deps-0.1.0.tar.bz2) set(run_codecheck true) elseif (${example} STREQUAL "core_child") set(example_tarball_name ignition-core_child-0.1.0.tar.bz2) set(run_codecheck true) elseif (${example} STREQUAL "core_child_private") set(example_tarball_name ignition-core_child_private-0.1.0.tar.bz2) set(run_codecheck true) elseif (${example} STREQUAL "comp_deps") set(example_tarball_name ignition-component_deps-0.1.0.tar.bz2) elseif (${example} STREQUAL "use_component_depsA") set(example_tarball_name ignition-use_component_depsa-0.1.0.tar.bz2) elseif (${example} STREQUAL "use_component_depsB") set(example_tarball_name ignition-use_component_depsb-0.1.0.tar.bz2) elseif (${example} STREQUAL "use_component_depsC") set(example_tarball_name ignition-use_component_depsc-0.1.0.tar.bz2) else() set(example_tarball_name) endif() foreach (build_type ${build_types}) set(TEST_NAME ${example}_${build_type}) string(TIMESTAMP TEST_TIME) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/junit_pass.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}_pass.xml" @ONLY) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/junit_fail.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/test_results/${TEST_NAME}.xml" @ONLY) set(example_INSTALL_DIR ${CMAKE_BINARY_DIR}/install/${build_type}) ExternalProject_Add( ${TEST_NAME} DEPENDS FAKE_INSTALL SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${example}" # BUILD_ALWAYS needed since cmake doesn't notice when # example files change. # See alternate approach in a2113e0997c9 if this becomes too slow BUILD_ALWAYS 1 CMAKE_ARGS "-DCMAKE_PREFIX_PATH=${FAKE_INSTALL_PREFIX};${example_INSTALL_DIR}" "-DCMAKE_BUILD_TYPE=${build_type}" "-DCMAKE_INSTALL_PREFIX=${example_INSTALL_DIR}" TEST_COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}_pass.xml" "${CMAKE_CURRENT_BINARY_DIR}/test_results/${TEST_NAME}.xml" ) if (${run_codecheck} AND TARGET codecheck) if(CMAKE_GENERATOR MATCHES "Unix Makefiles") ExternalProject_Add_Step( ${TEST_NAME} codecheck COMMAND $(MAKE) -C codecheck DEPENDEES configure ) else() ExternalProject_Add_Step( ${TEST_NAME} codecheck COMMAND ${CMAKE_COMMAND} --build --target codecheck DEPENDEES configure ) endif() endif() if (CPACK_GENERATOR) if(CMAKE_GENERATOR MATCHES "Unix Makefiles") ExternalProject_Add_Step( ${TEST_NAME} package_source COMMAND $(MAKE) -C package_source DEPENDEES configure ) else() ExternalProject_Add_Step( ${TEST_NAME} package_source COMMAND ${CMAKE_COMMAND} --build --target package_source DEPENDEES configure ) endif() ExternalProject_Add_Step( ${TEST_NAME} test_tarball_name COMMAND ${CMAKE_COMMAND} -E tar tf /${example_tarball_name} DEPENDEES package_source DEPENDERS test ) endif() add_test( ${TEST_NAME} ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/test_results/${TEST_NAME}.xml" "${CMAKE_BINARY_DIR}/test_results/${TEST_NAME}.xml" ) endforeach() endforeach() # dependencies between external projects # hard to use DEPENDS in ExternalProject_Add because targets # need to exist before they can be used there foreach (build_type ${build_types}) add_dependencies(core_child_${build_type} core_nodep_${build_type}) add_dependencies(core_child_private_${build_type} core_nodep_${build_type}) if (TARGET use_component_depsA_${build_type}) add_dependencies(use_component_depsA_${build_type} comp_deps_${build_type}) endif() if (TARGET use_component_depsB_${build_type}) add_dependencies(use_component_depsB_${build_type} comp_deps_${build_type}) endif() if (TARGET use_component_depsC_${build_type}) add_dependencies(use_component_depsC_${build_type} comp_deps_${build_type}) endif() endforeach() # test that core_child pkg-config file requires core_nodep # and that core_child_private pkg-config file requires core_nodep privately if (UNIX) set(TEST_NAME core_child_requires_core_nodep) string(TIMESTAMP TEST_TIME) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/junit_pass.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}_pass.xml" @ONLY) configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/junit_fail.xml.in" "${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME}_fail.xml" @ONLY) set(_env_vars) # On Debian and if the install prefix is /usr, the default CMAKE_INSTALL_LIBDIR of this project # as set by GNUInstallDirs will be different from the one of the example project, # so let's hardcode it in that case if(EXISTS "/etc/debian_version" AND "${CMAKE_INSTALL_PREFIX}" MATCHES "^/usr/?$") set(example_PKGCONFIG_INSTALL_LIBDIR "lib/pkgconfig") else() set(example_PKGCONFIG_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}/pkgconfig") endif() list(APPEND _env_vars "PKG_CONFIG_PATH=${example_INSTALL_DIR}/${example_PKGCONFIG_INSTALL_LIBDIR}:${FAKE_INSTALL_PREFIX}/${example_PKGCONFIG_INSTALL_LIBDIR}:$PKG_CONFIG_PATH") add_test(${TEST_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/test_core_child_requires_core_no_deps.bash ) set_tests_properties(${TEST_NAME} PROPERTIES ENVIRONMENT "${_env_vars}") endif() ign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/0000775000175000017500000000000014160533245024057 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/src/0000775000175000017500000000000014160533245024646 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/src/CMakeLists.txt0000664000175000017500000000043114160533245027404 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} PRIVATE ignition-core_no_deps::ignition-core_no_deps) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/src/empty.cc0000664000175000017500000000115614160533245026316 0ustar jriverojrivero/* * Copyright (C) 2020 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/CMakeLists.txt0000664000175000017500000000060614160533245026621 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-core_child_private VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_find_package(ignition-core_no_deps PRIVATE REQUIRED) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs(TAGFILES "${IGNITION-CORE_NO_DEPS_DOXYGEN_TAGFILE} = ${IGNITION-CORE_NO_DEPS_API_URL}") ign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/test/0000775000175000017500000000000014160533245025036 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/test/CMakeLists.txt0000664000175000017500000000000014160533245027564 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/README.md0000664000175000017500000000000014160533245025324 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/include/0000775000175000017500000000000014160533245025502 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child_private/include/CMakeLists.txt0000664000175000017500000000000014160533245030230 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/0000775000175000017500000000000014160533245024224 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/src/0000775000175000017500000000000014160533245025013 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/src/CMakeLists.txt0000664000175000017500000000044214160533245027553 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ignition-component_deps::ignition-component_deps-child) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/src/empty.cc0000664000175000017500000000115514160533245026462 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/CMakeLists.txt0000664000175000017500000000050314160533245026762 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-use_component_depsA VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_find_package(ignition-component_deps REQUIRED COMPONENTS parent child) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsA/README.md0000664000175000017500000000027414160533245025506 0ustar jriverojrivero# use\_component\_depsA This package uses the `child` and `parent` components of `component\_deps` and calls `ign_find_package` with the components specified in the order `parent child`. ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/0000775000175000017500000000000014160533245024225 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/src/0000775000175000017500000000000014160533245025014 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/src/CMakeLists.txt0000664000175000017500000000044214160533245027554 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ignition-component_deps::ignition-component_deps-child) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/src/empty.cc0000664000175000017500000000115514160533245026463 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/CMakeLists.txt0000664000175000017500000000050314160533245026763 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-use_component_depsB VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_find_package(ignition-component_deps REQUIRED COMPONENTS child parent) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsB/README.md0000664000175000017500000000045414160533245025507 0ustar jriverojrivero# use\_component\_depsB This package uses the `child` and `parent` components of `component\_deps` and calls `ign_find_package` with the components specified in the order `child parent`. Aside from the order in which the components are specified, this package is identical to `use_component_depsA`. ign-cmake-ignition-cmake2_2.10.0/examples/test_core_child_requires_core_no_deps.bash0000775000175000017500000000271414160533245030670 0ustar jriverojrivero#!/bin/bash TEST_STATUS=0 echo echo Expect ignition-core_child to require ignition-core_no_deps pkg-config ignition-core_child --print-requires if ! pkg-config ignition-core_child --print-requires \ | grep ignition-core_no_deps then echo oops TEST_STATUS=1 fi echo echo Expect ignition-core_child to not privately require ignition-core_no_deps pkg-config ignition-core_child --print-requires-private if pkg-config ignition-core_child --print-requires-private \ | grep ignition-core_no_deps then echo oops TEST_STATUS=1 fi echo echo Expect ignition-core_child_private to privately require ignition-core_no_deps pkg-config ignition-core_child_private --print-requires-private if ! pkg-config ignition-core_child_private --print-requires-private \ | grep ignition-core_no_deps then echo oops TEST_STATUS=1 fi echo echo Expect ignition-core_child_private to not require ignition-core_no_deps pkg-config ignition-core_child_private --print-requires if pkg-config ignition-core_child_private --print-requires \ | grep ignition-core_no_deps then echo oops TEST_STATUS=1 fi echo if [[ $TEST_STATUS -eq 0 ]] then echo Successfully detected ignition-core_nodep requirements cp core_child_requires_core_nodep_pass.xml ../test_results/core_child_requires_core_nodep.xml exit 0 else echo Could not detect all ignition-core_nodep requirements correctly cp core_child_requires_core_nodep_fail.xml ../test_results/core_child_requires_core_nodep.xml exit 1 fi ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/0000775000175000017500000000000014160533245024123 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/src/0000775000175000017500000000000014160533245024712 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/src/CMakeLists.txt0000664000175000017500000000025014160533245027447 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/src/AlmostEmpty.cc0000664000175000017500000000145214160533245027501 0ustar jriverojrivero/* * Copyright (C) 2021 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include namespace no_ignition_prefix { class IGNITION_NO_IGNITION_PREFIX_VISIBLE AlmostEmpty { }; } ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/CMakeLists.txt0000664000175000017500000000045214160533245026664 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(no_ignition_prefix VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project( NO_IGNITION_PREFIX REPLACE_IGNITION_INCLUDE_PATH no_ign) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/test/0000775000175000017500000000000014160533245025102 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/test/CMakeLists.txt0000664000175000017500000000000014160533245027630 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/README.md0000664000175000017500000000163414160533245025406 0ustar jriverojrivero# no\_ignition\_prefix example ## Configuring project name This package uses the `NO_IGNITION_PREFIX` option in `ign_configure_project` to allow a cmake package name without the `ignition-` prefix. To confirm, configure this package and `package_source` and then observe that the tarball, pkg-config `.pc` file, and cmake config files omit the `ignition-` prefix: ~~~ mkdir build cd build cmake .. make package_source ~~~ * `no_ignition_prefix-0.1.0.tar.bz2` * `cmake/no_ignition_prefix-config.cmake` * `cmake/pkgconfig/no_ignition_prefix.pc` ## Configuring include directory names This package uses the `REPLACE_IGNITION_INCLUDE_PATH` option in `ign_configure_project` to allow a custom include path of `no_ign`, which doesn't start with `ignition/`. To confirm, build the package and observe that `AlmostEmpty.cc` compiles successfully while including `no_ign/Export.hh`: ~~~ mkdir build cd build cmake .. make ~~~ ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/include/0000775000175000017500000000000014160533245025546 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/include/no_ign/0000775000175000017500000000000014160533245027017 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/include/no_ign/CMakeLists.txt0000664000175000017500000000003214160533245031552 0ustar jriverojriveroign_install_all_headers() ign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/include/no_ign/config.hh.in0000664000175000017500000000000014160533245031200 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/no_ignition_prefix/include/CMakeLists.txt0000664000175000017500000000003114160533245030300 0ustar jriverojriveroadd_subdirectory(no_ign) ign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/0000775000175000017500000000000014160533245022347 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/src/0000775000175000017500000000000014160533245023136 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/src/CMakeLists.txt0000664000175000017500000000025014160533245025673 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/src/AlmostEmpty.cc0000664000175000017500000000142314160533245025723 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include namespace ignition { namespace core_no_deps { class IGNITION_CORE_NO_DEPS_VISIBLE AlmostEmpty { }; } } ign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/CMakeLists.txt0000664000175000017500000000036114160533245025107 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-core_no_deps VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/test/0000775000175000017500000000000014160533245023326 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/test/CMakeLists.txt0000664000175000017500000000000014160533245026054 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/README.md0000664000175000017500000000000014160533245023614 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/include/0000775000175000017500000000000014160533245023772 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_nodep/include/CMakeLists.txt0000664000175000017500000000000014160533245026520 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/junit_fail.xml.in0000664000175000017500000000066414160533245023513 0ustar jriverojrivero ign-cmake-ignition-cmake2_2.10.0/examples/core_child/0000775000175000017500000000000014160533245022325 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/src/0000775000175000017500000000000014160533245023114 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/src/CMakeLists.txt0000664000175000017500000000043014160533245025651 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ignition-core_no_deps::ignition-core_no_deps) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/core_child/src/empty.cc0000664000175000017500000000115614160533245024564 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/core_child/CMakeLists.txt0000664000175000017500000000056614160533245025074 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-core_child VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_find_package(ignition-core_no_deps REQUIRED) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs(TAGFILES "${IGNITION-CORE_NO_DEPS_DOXYGEN_TAGFILE} = ${IGNITION-CORE_NO_DEPS_API_URL}") ign-cmake-ignition-cmake2_2.10.0/examples/core_child/test/0000775000175000017500000000000014160533245023304 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/test/CMakeLists.txt0000664000175000017500000000000014160533245026032 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/README.md0000664000175000017500000000000014160533245023572 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/include/0000775000175000017500000000000014160533245023750 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/core_child/include/CMakeLists.txt0000664000175000017500000000000014160533245026476 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/0000775000175000017500000000000014160533245022014 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/src/0000775000175000017500000000000014160533245022603 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/src/CMakeLists.txt0000664000175000017500000000000014160533245025331 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/CMakeLists.txt0000664000175000017500000000030514160533245024552 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-minimal0 VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_configure_build(QUIT_IF_BUILD_ERRORS) ign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/test/0000775000175000017500000000000014160533245022773 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/test/CMakeLists.txt0000664000175000017500000000000014160533245025521 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/README.md0000664000175000017500000000000014160533245023261 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/include/0000775000175000017500000000000014160533245023437 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/ign_conf/include/CMakeLists.txt0000664000175000017500000000000014160533245026165 0ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/0000775000175000017500000000000014160533245024226 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/src/0000775000175000017500000000000014160533245025015 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/src/CMakeLists.txt0000664000175000017500000000044214160533245027555 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources} CXX_STANDARD 11) target_link_libraries(${PROJECT_LIBRARY_TARGET_NAME} PUBLIC ignition-component_deps::ignition-component_deps-child) ign_build_tests(TYPE UNIT SOURCES ${gtest_sources}) ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/src/empty.cc0000664000175000017500000000115514160533245026464 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/CMakeLists.txt0000664000175000017500000000047414160533245026773 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-use_component_depsC VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_find_package(ignition-component_deps REQUIRED COMPONENTS child) ign_configure_build(QUIT_IF_BUILD_ERRORS) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/use_component_depsC/README.md0000664000175000017500000000021614160533245025504 0ustar jriverojrivero# use\_component\_depsC This package uses the `child` component of `component\_deps` but should also find the `parent` component indirectly. ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/0000775000175000017500000000000014160533245022203 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/src/0000775000175000017500000000000014160533245022772 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/src/CMakeLists.txt0000664000175000017500000000014514160533245025532 0ustar jriverojriveroign_get_libsources_and_unittests(sources gtest_sources) ign_create_core_library(SOURCES ${sources}) ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/src/AlmostEmpty.cc0000664000175000017500000000143114160533245025556 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include namespace ignition { namespace component_deps { class IGNITION_COMPONENT_DEPS_VISIBLE AlmostEmpty { }; } } ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/CMakeLists.txt0000664000175000017500000000041514160533245024743 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-component_deps VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) ign_configure_project() ign_configure_build(QUIT_IF_BUILD_ERRORS COMPONENTS child parent) ign_create_packages() ign_create_docs() ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/README.md0000664000175000017500000000024014160533245023456 0ustar jriverojrivero# component\_deps A package with two components (`child` and `parent`) with a dependency relationship between the components (`child` links against `parent`). ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/parent/0000775000175000017500000000000014160533245023474 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/parent/CMakeLists.txt0000664000175000017500000000021614160533245026233 0ustar jriverojrivero ign_add_component(parent INTERFACE GET_TARGET_NAME parent) install( DIRECTORY include/ DESTINATION "${IGN_INCLUDE_INSTALL_DIR_FULL}") ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/parent/include/0000775000175000017500000000000014160533245025117 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/parent/include/empty.hh0000664000175000017500000000115514160533245026600 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/child/0000775000175000017500000000000014160533245023266 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/child/CMakeLists.txt0000664000175000017500000000040214160533245026022 0ustar jriverojrivero ign_add_component(child INTERFACE DEPENDS_ON_COMPONENTS parent GET_TARGET_NAME child) target_link_libraries(${child} INTERFACE ${PROJECT_LIBRARY_TARGET_NAME}-parent) install( DIRECTORY include/ DESTINATION "${IGN_INCLUDE_INSTALL_DIR_FULL}") ign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/child/include/0000775000175000017500000000000014160533245024711 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/comp_deps/child/include/empty.hh0000664000175000017500000000115514160533245026372 0ustar jriverojrivero/* * Copyright (C) 2018 Open Source Robotics Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ ign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/0000775000175000017500000000000014160533245022250 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/ogre-2.1/0000775000175000017500000000000014160533245023502 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/ogre-2.1/CMakeLists.txt0000664000175000017500000000131614160533245026243 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-ogre-2.1 VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) message(STATUS "Finding OGRE 2.1") ign_find_package(IgnOGRE2 VERSION 2.1.0 COMPONENTS HlmsPbs HlmsUnlit Overlay) message(STATUS "OGRE2_FOUND: " ${OGRE2_FOUND}) message(STATUS "OGRE2_LIBRARIES: " ${OGRE2_LIBRARIES}) message(STATUS "OGRE2_INCLUDE_DIRS: " ${OGRE2_INCLUDE_DIRS}) message(STATUS "OGRE2_VERSION: " ${OGRE2_VERSION}) message(STATUS "OGRE2_VERSION_MAJOR: " ${OGRE2_VERSION_MAJOR}) message(STATUS "OGRE2_VERSION_MINOR: " ${OGRE2_VERSION_MINOR}) message(STATUS "OGRE2_VERSION_PATCH: " ${OGRE2_VERSION_PATCH}) message(STATUS "OGRE2_RESOURCE_PATH: " ${OGRE2_RESOURCE_PATH}) ign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/README.md0000664000175000017500000000236314160533245023533 0ustar jriverojriveroA quick demonstration of searching for Ogre 2.1 vs 2.2 via ign-cmake. To test with both versions installed: ## Ogre 2.1 ``` cd ogre-2.1 mkdir build cd build cmake .. ``` ### Expected output ``` -- Looking for IgnOGRE2 - found -- OGRE2_FOUND: TRUE -- OGRE2_LIBRARIES: /usr/lib/x86_64-linux-gnu/OGRE-2.1/libOgreMain.soIgnOGRE2-HlmsPbs::IgnOGRE2-HlmsPbsIgnOGRE2-HlmsUnlit::IgnOGRE2-HlmsUnlitIgnOGRE2-Overlay::IgnOGRE2-Overlay -- OGRE2_INCLUDE_DIRS: /usr/include/OGRE-2.1/usr/include/OGRE-2.1/RenderSystems/GL3Plus -- OGRE2_VERSION: 2.1.0 -- OGRE2_VERSION_MAJOR: 2 -- OGRE2_VERSION_MINOR: 1 -- OGRE2_VERSION_PATCH: 0 -- OGRE2_RESOURCE_PATH: /usr/lib/x86_64-linux-gnu/OGRE-2.1/OGRE ``` ## Ogre 2.2 ``` cd ogre-2.2 mkdir build cd build cmake .. ``` ### Expected output ``` -- Looking for IgnOGRE2 - found -- OGRE2_FOUND: TRUE -- OGRE2_LIBRARIES: /usr/lib/x86_64-linux-gnu/OGRE-2.2/libOgreMain.soIgnOGRE2-HlmsPbs::IgnOGRE2-HlmsPbsIgnOGRE2-HlmsUnlit::IgnOGRE2-HlmsUnlitIgnOGRE2-Overlay::IgnOGRE2-Overlay -- OGRE2_INCLUDE_DIRS: /usr/include/OGRE-2.2/usr/include/OGRE-2.2/RenderSystems/GL3Plus -- OGRE2_VERSION: 2.2.6 -- OGRE2_VERSION_MAJOR: 2 -- OGRE2_VERSION_MINOR: 2 -- OGRE2_VERSION_PATCH: 6 -- OGRE2_RESOURCE_PATH: /usr/lib/x86_64-linux-gnu/OGRE-2.2/OGRE ``` ign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/ogre-2.2/0000775000175000017500000000000014160533245023503 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/examples/find_ogre2/ogre-2.2/CMakeLists.txt0000664000175000017500000000131614160533245026244 0ustar jriverojriverocmake_minimum_required(VERSION 3.10.2 FATAL_ERROR) project(ignition-ogre-2.2 VERSION 0.1.0) find_package(ignition-cmake2 REQUIRED) message(STATUS "Finding OGRE 2.2") ign_find_package(IgnOGRE2 VERSION 2.2.0 COMPONENTS HlmsPbs HlmsUnlit Overlay) message(STATUS "OGRE2_FOUND: " ${OGRE2_FOUND}) message(STATUS "OGRE2_LIBRARIES: " ${OGRE2_LIBRARIES}) message(STATUS "OGRE2_INCLUDE_DIRS: " ${OGRE2_INCLUDE_DIRS}) message(STATUS "OGRE2_VERSION: " ${OGRE2_VERSION}) message(STATUS "OGRE2_VERSION_MAJOR: " ${OGRE2_VERSION_MAJOR}) message(STATUS "OGRE2_VERSION_MINOR: " ${OGRE2_VERSION_MINOR}) message(STATUS "OGRE2_VERSION_PATCH: " ${OGRE2_VERSION_PATCH}) message(STATUS "OGRE2_RESOURCE_PATH: " ${OGRE2_RESOURCE_PATH}) ign-cmake-ignition-cmake2_2.10.0/test/0000775000175000017500000000000014160533245017373 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/test/CMakeLists.txt0000664000175000017500000000036014160533245022132 0ustar jriverojriveroif (UNIX) add_test(cmake_minimum_required_match bash ${CMAKE_CURRENT_SOURCE_DIR}/cmake_minimum_required.bash ${CMAKE_SOURCE_DIR} --xml_output_dir ${CMAKE_BINARY_DIR}/test_results ) endif() add_subdirectory(warning) ign-cmake-ignition-cmake2_2.10.0/test/warning/0000775000175000017500000000000014160533245021040 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/test/warning/CMakeLists.txt0000664000175000017500000000106214160533245023577 0ustar jriverojrivero ign_get_sources(tests) foreach(test ${tests}) get_filename_component(name ${test} NAME_WE) set(name WARNING_${name}) add_executable(${name} ${test}) target_link_libraries(${name} ${PROJECT_EXPORT_NAME}-utilities) set_property(TARGET ${name} PROPERTY CXX_STANDARD 11) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") target_compile_options(${name} PRIVATE "-Wall" "-Werror") elseif(MSVC) target_compile_options(${name} PRIVATE "/W4" "/WX" "/we4265" "/EHsc") endif() endforeach() ign-cmake-ignition-cmake2_2.10.0/test/warning/nonvirtual_destructor.cc0000664000175000017500000000101514160533245026023 0ustar jriverojrivero #include #include class Base { virtual std::string printStuff() = 0; }; IGN_UTILS_WARN_IGNORE__NON_VIRTUAL_DESTRUCTOR class Derived : public Base { std::string stuff; std::string printStuff() override { return stuff; } }; IGN_UTILS_WARN_RESUME__NON_VIRTUAL_DESTRUCTOR Base *MakeDerived() { return new Derived; } int main() { Base *b = MakeDerived(); IGN_UTILS_WARN_IGNORE__NON_VIRTUAL_DESTRUCTOR delete b; IGN_UTILS_WARN_RESUME__NON_VIRTUAL_DESTRUCTOR } ign-cmake-ignition-cmake2_2.10.0/test/cmake_minimum_required.bash0000775000175000017500000000554114160533245024755 0ustar jriverojrivero#!/bin/bash # Verify that cmake_minimum_required statements have matching version numbers export CMAKE_FILES_TO_CHECK=" $1/CMakeLists.txt $1/cmake/ignition-all-config.cmake.in $1/cmake/ignition-component-config.cmake.in $1/cmake/ignition-config.cmake.in $1/config/ignition-cmake-config.cmake.in" unset TEST_CMAKE_MIN_REQUIRED_FAILED # first argument is root of ign-cmake repository if [[ ! -d "$1" \ || ! -a "$1/CMakeLists.txt" \ || ! -a "$1/cmake/ignition-all-config.cmake.in" \ || ! -a "$1/cmake/ignition-component-config.cmake.in" \ || ! -a "$1/cmake/ignition-config.cmake.in" \ || ! -a "$1/config/ignition-cmake-config.cmake.in" ]]; then echo the first argument must be the root of the ign-cmake repository export TEST_CMAKE_MIN_REQUIRED_FAILED=1 else grep -h '^cmake_minimum_required' $CMAKE_FILES_TO_CHECK \ | uniq -c \ | awk '{ if ($1 != "5") { exit 1 }}' \ || \ export TEST_CMAKE_MIN_REQUIRED_FAILED=1 fi if test "$2" = "--xml_output_dir"; then xml_output_dir=$3 if [[ ! -a "${xml_output_dir}" ]]; then mkdir -p "${xml_output_dir}" fi if [[ ! -d "${xml_output_dir}" ]]; then echo If using --xml_output_dir, the 3rd argument must be a directory. exit 1 fi if [[ -z ${TEST_CMAKE_MIN_REQUIRED_FAILED} ]]; then cat < ${xml_output_dir}/cmake_minimum_required.xml END else cat < ${xml_output_dir}/cmake_minimum_required.xml > ${xml_output_dir}/cmake_minimum_required.xml cat <> ${xml_output_dir}/cmake_minimum_required.xml ]]> END exit 1 fi else echo Verify that cmake_minimum_required statements have matching version numbers grep -n '^cmake_minimum_required' $CMAKE_FILES_TO_CHECK \ | sed -e 's@^@ @' if [[ -z ${TEST_CMAKE_MIN_REQUIRED_FAILED} ]]; then echo --------------------------- Passed --------------------------- else echo --------------------------- Failed --------------------------- exit 1 fi fi ign-cmake-ignition-cmake2_2.10.0/tutorials/0000775000175000017500000000000014160533245020442 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/tutorials/index.md0000664000175000017500000000031014160533245022065 0ustar jriverojrivero# Introduction Ignition CMake is a component in the Ignition framework, a set of libraries designed to rapidly develop robot applications. [http://ignitionrobotics.org](http://ignitionrobotics.org) ign-cmake-ignition-cmake2_2.10.0/tutorials/install.md0000664000175000017500000002013714160533245022435 0ustar jriverojrivero\page install Installation These instructions are for installing only Ignition CMake. If you're interested in using all the Ignition libraries, not only Igniton CMake, check out this [Ignition installation](https://ignitionrobotics.org/docs/latest/install). We recommend following the binary install instructions to get up and running as quickly and painlessly as possible. The source install instructions should be used if you need the very latest software improvements, if you need to modify the code, or if you plan to make a contribution. # Binary Install ## Ubuntu On Ubuntu, it's possible to install Ignition CMake as follows: Add OSRF packages: ``` echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys D2486D2DD83DB69272AFE98867170598AF249743 sudo apt update ``` Install Ignition CMake: ``` sudo apt install libignition-cmake<#>-dev ``` Be sure to replace `<#>` with a number value, such as 1 or 2, depending on which version you need. ## macOS On macOS, add OSRF packages: ``` ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" brew tap osrf/simulation ``` Install Ignition CMake: ``` brew install ignition-cmake<#> ``` Be sure to replace `<#>` with a number value, such as 1 or 2, depending on which version you need. ## Windows Install [Conda package management system](https://docs.conda.io/projects/conda/en/latest/user-guide/install/download.html). Miniconda suffices. Open a Visual Studio Command Prompt (search for "x64 Native Tools Command Prompt for VS 2019" in the Windows search near the Start button). Optionally, right-click and pin to the task bar for quick access in the future. If you did not add Conda to your `PATH` environment variable during Conda installation, you may need to navigate to the location of `condabin` in order to use the `conda` command. To find `condabin`, search for "Anaconda Prompt" in the Windows search near the Start button, open it, run `where conda`, and look for a line containing the directory `condabin`. 1. Navigate to your `condabin` if necessary, and then create and activate a Conda environment: ``` conda create -n ign-ws conda activate ign-ws ``` Once you have activated an environment, a prefix like `(ign-ws)` will be prepended to your prompt, and you can use the `conda` command outside of `condabin`. You can use `conda info --envs` to see all your environments. To remove an environment, use `conda env remove --name `. 2. Install Ignition CMake: ``` conda install libignition-cmake<#> --channel conda-forge ``` Be sure to replace `<#>` with a number value, such as 1 or 2, depending on which version you need. You can view all the versions with ``` conda search libignition-cmake* --channel conda-forge ``` and view their dependencies with ``` conda search libignition-cmake* --channel conda-forge --info ``` and install a specific minor version with ``` conda install libignition-cmake=2.6.1 --channel conda-forge ``` # Source Install ## Ubuntu Bionic 18.04 or above ### Prerequisites Add OSRF packages: ``` sudo apt update sudo apt -y install wget lsb-release gnupg sh -c 'echo "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable `lsb_release -cs` main" > /etc/apt/sources.list.d/gazebo-stable.list' wget http://packages.osrfoundation.org/gazebo.key -O - | apt-key add - sudo apt-add-repository -s "deb http://packages.osrfoundation.org/gazebo/ubuntu-stable $(lsb_release -c -s) main" ``` Only on Bionic, update the GCC compiler version: ``` sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-8 800 --slave /usr/bin/g++ g++ /usr/bin/g++-8 --slave /usr/bin/gcov gcov /usr/bin/gcov-8 ``` ### Building from source Clone source code: ``` # This checks out the `main` branch. You can append `-b ign-cmake#` (replace # with a number) to checkout a specific version git clone http://github.com/ignitionrobotics/ign-cmake ``` Install dependencies ``` sudo apt -y install $(sort -u $(find . -iname 'packages.apt') | tr '\n' ' ') ``` Build and install as follows: ``` cd ign-cmake mkdir build cd build cmake .. make -j4 sudo make install ``` ## Windows 10 ### Prerequisites 1. Install [Conda package management system](https://docs.conda.io/projects/conda/en/latest/user-guide/install/download.html). Miniconda suffices. 2. Install [Visual Studio 2019](https://visualstudio.microsoft.com/downloads/). The Community version is free for students, open-source contributors, and individuals. Check "Desktop development with C++" in the "Workloads" tab, and uncheck "C++ CMake Tools". We will install `cmake` via Conda. ### Building from source Open a Visual Studio Command Prompt (search for "x64 Native Tools Command Prompt for VS 2019" in the search field near the Windows button). Optionally, right-click and pin to the task bar for quick access in the future. If you did not add Conda to your `PATH` environment variable during Conda installation, you may need to navigate to the location of `condabin` in order to use the `conda` command. To find `condabin`, search for "Anaconda Prompt" in the search field near the Windows button, open it, run `where conda`, and look for a line containing the directory `condabin`. 1. Navigate to your `condabin` if necessary, and then create and activate a Conda environment: ``` conda create -n ign-ws conda activate ign-ws ``` Once you have activated an environment, a prefix like `(ign-ws)` will be prepended to your prompt, and you can use the `conda` command outside of `condabin`. You can use `conda info --envs` to see all your environments. To remove an environment, use `conda env remove --name `. 2. Install dependencies ``` conda install git cmake pkg-config --channel conda-forge ``` 3. Navigate to where you would like to build the library, and then clone the repository. ``` # Optionally, append `-b ign-cmake#` (replace # with a number) to check out a specific version git clone https://github.com/ignitionrobotics/ign-cmake.git ``` 4. Build. ``` cd ign-cmake mkdir build cd build cmake .. # Optionally, -DCMAKE_INSTALL_PREFIX=path\to\install cmake --build . --config Release cmake --install . --config Release ``` **Note** If you find that the build is failing due to failures in the `test` directory, then you may need to disable tests by adding `-DBUILD_TESTING=OFF` to the `cmake ..` command. # Documentation API documentation and tutorials can be accessed at [https://ignitionrobotics.org/libs/cmake](https://ignitionrobotics.org/libs/cmake) You can also generate the documentation from a clone of this repository by following these steps. 1. You will need [Doxygen](http://www.doxygen.org/). On Ubuntu Doxygen can be installed using ``` sudo apt-get install doxygen ``` 2. Clone the repository ``` git clone https://github.com/ignitionrobotics/ign-cmake ``` 3. Configure and build the documentation. ``` cd ign-cmake mkdir build cd build cmake .. make doc ``` 4. View the documentation by running the following command from the `build` directory. ``` firefox doxygen/html/index.html ``` **Note** Alternatively, documentation for `ignition-cmake` can be found within the source code, and also in the [MIGRATION.md guide](https://github.com/ignitionrobotics/ign-cmake/blob/main/MIGRATION.md). # Testing Follow these steps to run tests and static code analysis in your clone of this repository. 1. Follow the [source install instruction](#source-install). 2. Run tests. ``` make test ``` 3. Static code checker. ``` make codecheck ``` Additionally, a fuller suite of tests in the `examples` directory can be enabled by building with `BUILDSYSTEM_TESTING` enabled. Tests can be run by building the `test` target. From your build directory you can run: ``` $ cmake .. -DBUILDSYSTEM_TESTING=1 $ make test ``` See the [Writing Tests section of the ign-cmake contributor documentation](https://ignitionrobotics.org/docs/all/contributing#writing-tests) for help creating or modifying tests. ign-cmake-ignition-cmake2_2.10.0/tutorials/developing_with_ign-cmake.md0000664000175000017500000002425714160533245026100 0ustar jriverojrivero\page developingwithcmake Developing with Ignition CMake # Developing with Ignition CMake This tutorial documents various tips and strategies for developing with Ignition CMake. ## Helpful CMake flags There are several flags that control the results of the CMake tool. Some of these flags are built into CMake, where some are Ignition CMake specific. All of the following flags may be set as part of an individual CMake invocation. Alternatively, the flags may be passed to `colcon` using techniques described later in this document. ### Setting the build type The `CMAKE_BUILD_TYPE` variable controls the type of binary output from the build stage. This will have an impact on the flags passed to the compiler and linker. The available options are: * `RelWithDebInfo`: Mostly optimized build, but with debug symbols. * `Debug`: Debug build without optimizations, with debug symbols enabled. * `Release`: Fully optimized build, no debug symbols. * `MinSizeRel`: Fully optimized build, minimal binary size * `Coverage`: Build with additional information required for the [`gcov` analysis tool](https://en.wikipedia.org/wiki/Gcov) * `Profile`: Use flags that are helpful with the [`gprof` profiling tool](https://en.wikipedia.org/wiki/Gprof) More information about flags applied can be found in [IgnSetCompilerFlags.cmake](https://github.com/ignitionrobotics/ign-cmake/blob/ign-cmake2/cmake/IgnSetCompilerFlags.cmake) If left unspecified, `CMAKE_BUILD_TYPE` is set to `RelWithDebInfo` To change the build type, set the CMake flag: ``` -DCMAKE_BUILD_TYPE=Debug ``` ### Disabling or suppressing warnings about optional components Many ignition packages come with optional component libraries. These optional components will typically have additional dependencies that the package's core library does not require. If you are missing the dependencies of any optional components, you will receive a cmake warning like ``` -- Skipping component [component_name]: Missing dependency [dependency_name]. ^~~~~ Set SKIP_component_name=true in cmake to suppress this warning. ``` If you do not care about the specified component, you can safely ignore this warning. The configuration and build steps will succeed without any problem. The only side effect is the optional component will not be built. If you do want to build the optional component, then you will need to install whichever dependencies were said to be missing and then rerun cmake. If you do *not* want to build the optional component and you want to suppress the warning about the missing dependencies, you can set the cmake flag: ``` -DSKIP_component_name=true ``` where you should replace `component_name` with the actual name of the component as specified inside the angle brackets `[]` of the warning. ### Creating a compilation database `CMake` can optionally generate a compilation data base that may be used with a variety of code completion tools. By default, a compilation database is *not generated* To enable compilation database generation, set the CMake flag: ``` -DCMAKE_EXPORT_COMPILE_COMMANDS=ON ``` For more information about what the compilation database is, consult the [`clang` documentation](https://clang.llvm.org/docs/JSONCompilationDatabase.html) Some examples of utilities that can use the compilation database: * [`coc.vim`](https://github.com/neoclide/coc.nvim): Code completion for VIM * [`YouCompleteMe`](https://github.com/ycm-core/YouCompleteMe) Code completion for VIM ### Using the ninja build system Rather than using `make`, it may be desired to use the [Ninja](https://ninja-build.org/) build tool. By default `make` will be used. To change the build system type, set the CMake flag: ``` -GNinja ``` ### Address sanitizer (ASan) The `gcc` and `clang` compilers have a set of flags to generate instrumented builds for detecting memory leaks. By default, address sanitizer is *not used*. To enable address sanitizer, set all of the following flags: ``` -DCMAKE_CXX_FLAGS="-fsanitize=address -fsanitize=leak -g" -DCMAKE_C_FLAGS="-fsanitize=address -fsanitize=leak -g" -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address -fsanitize=leak" -DCMAKE_MODULE_LINKER_FLAGS="-fsanitize=address -fsanitize=leak" ``` This will report if memory is leaked during execution of binaries or tests. More information about address santizier can be found in the [ASan documentation](https://github.com/google/sanitizers/wiki/AddressSanitizer). Note: Address sanitizer may have an impact on the performance of execution. ### Using CCache When you are doing frequent rebuilds, you can use a program to cache intermediate compiler results. First, install [`ccache`](https://ccache.dev/) and configure it to an appropriate cache size for your system: ``` $ sudo apt update && sudo apt install ccache $ ccache -M10G Set cache size limit to 10.0 GB ``` Then set the CMake flags: ``` -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache ``` ### Enabling/Disabling Documentation When you are doing frequent rebuilds, it generally doesn't make sense to rebuild documentation each build. By default, building documentation is *enabled*. To disable building documentation, set the CMake flag: ``` -DBUILD_DOCS=OFF ``` ### Enabling/Disabling Tests If your intent is to only produce libraries and executables, it is possible to disables tests. By default, building tests is *enabled*. To disable building tests, set the CMake flag: ``` -DBUILD_TESTING=OFF ``` ### Enabling/Disabling Buildsystem Tests There are additional tests of the Ignition CMake buildsystem. It is recommend to run these tests when making modifications to the Ignition CMake codebase. By default, building buildsystem tests is *disabled*. To enable building buildsystem tests, set the CMake flags: ``` -DBUILD_TESTING=ON -DBUILDSYSTEM_TESTING=ON ``` ## Developing with Colcon and vcstool [`colcon`](https://colcon.readthedocs.io/en/released/) is a tool that improves the workflow of building and testing multiple software packages. As an Ignition collection is composed of multiple packages that are frequently built and tested together, `colcon` eases this workflow. The basic outline of obtaining Ignition source packages via `vcs` and building with `colcon` is available in the [Ignition source installation documentation](https://ignitionrobotics.org/docs/latest/install_ubuntu_src). ### Passing CMake flags via command line When performing `colcon` builds, flags may be passed to Ignition CMake to configure the build. This can be done via the `--cmake-args` flag in `colcon`: ``` colcon build --cmake-args -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ``` ### Passing colcon mixins via command line To ease configuration of common flags, `colcon` has a concept of `mixins`, that are flags that "shortcut" groups of behavior. The set of readily-available defaults is in the [colcon-mixin-repository](https://github.com/colcon/colcon-mixin-repository). To install: ``` $ colcon mixin add default https://raw.githubusercontent.com/colcon/colcon-mixin-repository/master/index.yaml $ colcon mixin update default $ colcon mixin show ``` An example of building with `colcon` with two mixins: * [`ccache` mixin](https://github.com/colcon/colcon-mixin-repository/blob/master/ccache.mixin) * [`rel-with-db-info` mixin](https://github.com/colcon/colcon-mixin-repository/blob/master/build-type.mixin) ``` colcon build --mixin ccache rel-with-deb-info ``` This will build with the flags applied from the requested mixins. Colcon allows you to create your own mixins for commonly-reused command line flags. For more information about creating mixins, consult the [`colcon mixin` documentation](https://colcon.readthedocs.io/en/released/reference/mixin-arguments.html) ### Using a defaults file It is useful to be able to apply a consistent set of flags across an entire Ignition collection when building. One mechanism for accomplishing this is a `defaults.yaml` file. This is a file of configuration options that `colcon` will read to customize the default behavior. More information about the `defaults.yaml` file can be found in the corresponding [`colcon` documentation](https://colcon.readthedocs.io/en/released/user/configuration.html#defaults-yaml) For the following, if you do not have `colcon` or `vcs` installed, consult the [Ignition source installation documentation](https://ignitionrobotics.org/docs/latest/install_ubuntu_src). To try this out, first create an Ignition source workspace: ``` mkdir -p ~/ign_edifice/src cd ~/ign_edifice/ wget https://raw.githubusercontent.com/ignition-tooling/gazebodistro/main/collection-edifice.yaml vcs import src < collection-edifice.yaml ``` Then add a `~/ign_edifice/defaults.yaml` file with compilation flags: ``` { "build": { "merge-install": true, "symlink-install": true, "cmake-args": [ "--no-warn-unused-cli", "-DCMAKE_EXPORT_COMPILE_COMMANDS=1", "-DCMAKE_BUILD_TYPE=RelWithDebInfo", ] } } ``` To build with this defaults file, first export the correct environment variable and execute colcon: ``` cd ~/ign_edifice export COLCON_DEFAULTS_FILE=`pwd`/defaults.yaml colcon build ``` ### Using a defaults file with mixins Mixins can also be applied via the `defaults.yaml` file: ``` { "build": { "merge-install": true, "symlink-install": true, "mixins": [ "compile-commands", "rel-with-deb-info", ] } } ``` ### Setting a per-workspace defaults file with direnv Optionally, defaults can be applied user-wide by placing a defaults file at `$COLCON_HOME/defaults.yaml` (which is `~/.colcon/defaults.yaml` by default). In order to manage per-workspace settings, a tool like [`direnv`](https://direnv.net/) can be used to automate the application of the environment variable. Once `direnv` is installed and configured with your shell of choice, do the following: ``` $ cd ~/ign_edifice/ # The environment variable will be unset $ echo $COLCON_DEFAULTS_FILE $ echo export COLCON_DEFAULTS_FILE=`pwd`/defaults.yaml > .envrc direnv: error .envrc is blocked, Run `direnv allow` to approve its content $ direnv allow direnv: loading ~/ign_edifice/.envrc direnv: export +COLCON_DEFAULTS_FILE $ echo $COLCON_DEFAULTS_FILE ~/ign_edifice/defaults.yaml ``` Once this is configured, the environment will be applied each time you navigate to the `~/ign_edifice` directory or its children. ign-cmake-ignition-cmake2_2.10.0/doc/0000775000175000017500000000000014160533245017161 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/doc/CMakeLists.txt0000664000175000017500000000012114160533245021713 0ustar jriverojriveroinstall(DIRECTORY doxygen/ DESTINATION ${IGN_DATA_INSTALL_DIR}/doxygen) ign-cmake-ignition-cmake2_2.10.0/doc/doxygen/0000775000175000017500000000000014160533245020636 5ustar jriverojriveroign-cmake-ignition-cmake2_2.10.0/doc/doxygen/footer.html0000664000175000017500000000005214160533245023017 0ustar jriverojrivero ign-cmake-ignition-cmake2_2.10.0/doc/doxygen/header.html0000664000175000017500000001411714160533245022760 0ustar jriverojrivero $projectname: $title
ign-cmake-ignition-cmake2_2.10.0/doc/doxygen/api.in0000664000175000017500000032001714160533245021742 0ustar jriverojrivero# Doxyfile 1.8.14 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. # # All text after a double hash (##) is considered a comment and is placed in # front of the TAG it is preceding. # # All text after a single hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all text # before the first occurrence of this tag. Doxygen uses libiconv (or the iconv # built into libc) for the transcoding. See # https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded by # double-quotes, unless you are using Doxywizard) that should identify the # project for which the documentation is generated. This name is used in the # title of most generated pages and in a few other places. # The default value is: My Project. PROJECT_NAME = "Ignition @IGN_DESIGNATION_CAP@" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version # control system is used. PROJECT_NUMBER = @PROJECT_VERSION_FULL@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. PROJECT_BRIEF = # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. OUTPUT_DIRECTORY = doxygen # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and # will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes # performance problems for the file system. # The default value is: NO. CREATE_SUBDIRS = NO # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode # U+3044. # The default value is: NO. ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, # Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), # Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, # Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), # Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, # Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, # Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, # Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. # The default value is: YES. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief # description of a member or function before the detailed description # # Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. # The default value is: YES. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator that is # used to form the text in various listings. Each string in this list, if found # as the leading text of the brief description, will be stripped from the text # and the result, after processing the whole list, is used as the annotated # text. Otherwise, the brief description is used as-is. If left blank, the # following values are used ($name is automatically replaced with the name of # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief # description. # The default value is: NO. ALWAYS_DETAILED_SEC = YES # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. # The default value is: NO. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the # shortest path that makes the file name unique will be used # The default value is: YES. FULL_PATH_NAMES = NO # The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. # Stripping is only done if one of the specified strings matches the left-hand # part of the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the path to # strip. # # Note that you can specify absolute paths here, but also relative paths, which # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which # header file to include in order to use a class. If left blank only the name of # the header file containing the class definition is used. Otherwise one should # specify the list of include paths that are normally passed to the compiler # using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't # support long names like on DOS, Mac, or CD-ROM. # The default value is: NO. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the # first line (until the first dot) of a Javadoc-style comment as the brief # description. If set to NO, the Javadoc-style will behave just like regular Qt- # style comments (thus requiring an explicit @brief command for a brief # description.) # The default value is: NO. JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus # requiring an explicit \brief command for a brief description.) # The default value is: NO. QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a # multi-line C++ special comment block (i.e. a block of //! or /// comments) as # a brief description. This used to be the default behavior. The new default is # to treat a multi-line C++ comment block as a detailed description. Set this # tag to YES if you prefer the old behavior instead. # # Note that setting this tag to YES also means that rational rose comments are # not recognized any more. # The default value is: NO. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new # page for each member. If set to NO, the documentation of a member will be part # of the file/class/namespace that contains it. # The default value is: NO. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # uses this value to replace tabs by spaces in code fragments. # Minimum value: 1, maximum value: 16, default value: 4. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that act as commands in # the documentation. An alias has the form: # name=value # For example adding # "sideeffect=@par Side Effects:\n" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all # members will be omitted, etc. # The default value is: NO. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or # Python sources only. Doxygen will then generate output that is more tailored # for that language. For instance, namespaces will be presented as packages, # qualified scopes will look different, etc. # The default value is: NO. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources. Doxygen will then generate output that is tailored for Fortran. # The default value is: NO. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for VHDL. # The default value is: NO. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, # C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: # FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: # Fortran. In the later case the parser tries to guess whether the code is fixed # or free formatted code, this is the default for Fortran type files), VHDL. For # instance to make doxygen treat .inc files as Fortran files (default is PHP), # and .f files as C (default is Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable # documentation. See http://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. # The default value is: YES. MARKDOWN_SUPPORT = YES # When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up # to that level are automatically included in the table of contents, even if # they do not have an id attribute. # Note: This feature currently applies only to Markdown headings. # Minimum value: 0, maximum value: 99, default value: 0. # This tag requires that the tag MARKDOWN_SUPPORT is set to YES. # TOC_INCLUDE_HEADINGS = 0 # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or # globally by setting AUTOLINK_SUPPORT to NO. # The default value is: YES. AUTOLINK_SUPPORT = YES # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should set this # tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); # versus func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. # The default value is: NO. BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. # The default value is: NO. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: # https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate # getter and setter methods for a property. Setting this option to YES will make # doxygen to replace the get and set methods by a property in the documentation. # This will only work if the methods are indeed getting or setting a simple # type. If this is not the case, or you want to show the methods anyway, you # should set this option to NO. # The default value is: YES. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. # The default value is: NO. DISTRIBUTE_GROUP_DOC = YES # If one adds a struct or class to a group and this option is enabled, then also # any nested class or struct is added to the same group. By default this option # is disabled and one has to add nested compounds explicitly via \ingroup. # The default value is: NO. GROUP_NESTED_COMPOUNDS = NO # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent # subgrouping. Alternatively, this can be done per class using the # \nosubgrouping command. # The default value is: YES. SUBGROUPING = YES # When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions # are shown inside the group in which they are included (e.g. using \ingroup) # instead of on a separate page (for HTML and Man pages) or section (for LaTeX # and RTF). # # Note that this feature does not work in combination with # SEPARATE_MEMBER_PAGES. # The default value is: NO. INLINE_GROUPED_CLASSES = NO # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in # the documentation of the scope in which they are defined (i.e. file, # namespace, or group documentation), provided this scope is documented. If set # to NO, structs, classes, and unions are shown on a separate page (for HTML and # Man pages) or section (for LaTeX and RTF). # The default value is: NO. INLINE_SIMPLE_STRUCTS = NO # When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or # enum is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically be # useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. # The default value is: NO. TYPEDEF_HIDES_STRUCT = NO # The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This # cache is used to resolve symbols given their name and scope. Since this can be # an expensive process and often the same symbol appears multiple times in the # code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small # doxygen will become slower. If the cache is too large, memory is wasted. The # cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range # is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 # symbols. At the end of a run doxygen will report the cache usage and suggest # the optimal cache size from a speed point of view. # Minimum value: 0, maximum value: 9, default value: 0. LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in # documentation are documented, even if no documentation was available. Private # class members and static file members will be hidden unless the # EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. # Note: This will also disable the warnings about undocumented members that are # normally produced when WARNINGS is set to YES. # The default value is: NO. EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will # be included in the documentation. # The default value is: NO. EXTRACT_PRIVATE = NO # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. EXTRACT_PACKAGE = NO # If the EXTRACT_STATIC tag is set to YES, all static members of a file will be # included in the documentation. # The default value is: NO. EXTRACT_STATIC = YES # If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined # locally in source files will be included in the documentation. If set to NO, # only classes defined in header files are included. Does not have any effect # for Java sources. # The default value is: YES. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. If set to YES, local methods, # which are defined in the implementation section but not in the interface are # included in the documentation. If set to NO, only methods in the interface are # included. # The default value is: NO. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base name of # the file that contains the anonymous namespace. By default anonymous namespace # are hidden. # The default value is: NO. EXTRACT_ANON_NSPACES = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation # section is generated. This option has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option # has no effect if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend # (class|struct|union) declarations. If set to NO, these declarations will be # included in the documentation. # The default value is: NO. HIDE_FRIEND_COMPOUNDS = YES # If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any # documentation blocks found inside the body of a function. If set to NO, these # blocks will be appended to the function's detailed documentation block. # The default value is: NO. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation that is typed after a # \internal command is included. If the tag is set to NO then the documentation # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with # their full class and namespace scopes in the documentation. If set to YES, the # scope will be hidden. # The default value is: NO. HIDE_SCOPE_NAMES = YES # If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will # append additional text to a page's title, such as Class Reference. If set to # YES the compound reference will be hidden. # The default value is: NO. HIDE_COMPOUND_REFERENCE= NO # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. SHOW_INCLUDE_FILES = YES # If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each # grouped member an include statement to the documentation, telling the reader # which file to include in order to use the member. # The default value is: NO. SHOW_GROUPED_MEMB_INC = NO # If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include # files with double quotes in the documentation rather than with sharp brackets. # The default value is: NO. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the # documentation for inline members. # The default value is: YES. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the # (detailed) documentation of file and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. # The default value is: YES. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief # descriptions of file, namespace and class members alphabetically by member # name. If set to NO, the members will appear in declaration order. Note that # this will also influence the order of the classes in the class list. # The default value is: NO. SORT_BRIEF_DOCS = YES # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the # (brief and detailed) documentation of class members so that constructors and # destructors are listed first. If set to NO the constructors will appear in the # respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. # Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief # member documentation. # Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting # detailed member documentation. # The default value is: NO. SORT_MEMBERS_CTORS_1ST = YES # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy # of group names into alphabetical order. If set to NO the group names will # appear in their defined order. # The default value is: NO. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by # fully-qualified names, including namespaces. If set to NO, the class list will # be sorted only by class name, not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the alphabetical # list. # The default value is: NO. SORT_BY_SCOPE_NAME = NO # If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper # type resolution of all parameters of a function it will reject a match between # the prototype and the implementation of a member function even if there is # only one candidate or it is obvious which candidate to choose by doing a # simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still # accept a match between prototype and implementation in such cases. # The default value is: NO. STRICT_PROTO_MATCHING = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo # list. This list is created by putting \todo commands in the documentation. # The default value is: YES. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test # list. This list is created by putting \test commands in the documentation. # The default value is: YES. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug # list. This list is created by putting \bug commands in the documentation. # The default value is: YES. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) # the deprecated list. This list is created by putting \deprecated commands in # the documentation. # The default value is: YES. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional documentation # sections, marked by \if ... \endif and \cond # ... \endcond blocks. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the # documentation. If the initializer consists of more lines than specified here # it will be hidden. Use a value of 0 to hide initializers completely. The # appearance of the value of individual variables and macros / defines can be # controlled using \showinitializer or \hideinitializer command in the # documentation regardless of this setting. # Minimum value: 0, maximum value: 10000, default value: 30. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated at # the bottom of the documentation of classes and structs. If set to YES, the # list will mention the files that were used to generate the documentation. # The default value is: YES. SHOW_USED_FILES = YES # Set the SHOW_FILES tag to NO to disable the generation of the Files page. This # will remove the Files entry from the Quick Index and from the Folder Tree View # (if specified). # The default value is: YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces # page. This will remove the Namespaces entry from the Quick Index and from the # Folder Tree View (if specified). # The default value is: YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command command input-file, where command is the value of the # FILE_VERSION_FILTER tag, and input-file is the name of an input file provided # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml # will be used as the name of the layout file. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. LAYOUT_FILE = "@IGNITION_CMAKE_DOXYGEN_DIR@/layout.xml" # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool # to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated to # standard output by doxygen. If QUIET is set to YES this implies that the # messages are off. # The default value is: NO. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated to standard error (stderr) by doxygen. If WARNINGS is set to YES # this implies that the warnings are on. # # Tip: Turn warnings on while writing the documentation. # The default value is: YES. WARNINGS = YES # If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate # warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag # will automatically be disabled. # The default value is: YES. WARN_IF_UNDOCUMENTED = NO # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some parameters # in a documented function, or documenting parameters that don't exist or using # markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete # parameter documentation, but not about the absence of documentation. # The default value is: NO. WARN_NO_PARAMDOC = YES # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when # a warning is encountered. # The default value is: NO. WARN_AS_ERROR = NO # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard # error (stderr). WARN_LOGFILE = ignition-doxygen.warn #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = @IGNITION_DOXYGEN_INPUT@ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv # documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # # If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, # *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, # *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, # *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, # *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf and *.qsf. FILE_PATTERNS = *.hh \ *.h \ *.md # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. # The default value is: NO. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should be # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. # # Note that relative paths are relative to the directory from which doxygen is # run. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded # from the input. # The default value is: NO. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* EXCLUDE_PATTERNS = *_TEST.* \ *_TEST[123456789]*.* \ win_dirent.h \ *Private.hh \ */detail/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test # # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* EXCLUDE_SYMBOLS = detail # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). EXAMPLE_PATH = @CMAKE_SOURCE_DIR@ # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and # *.h) to filter out the source-files in the directories. If left blank all # files are included. EXAMPLE_PATTERNS = *.cc \ *.hh \ CMakeLists.txt # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands # irrespective of the value of the RECURSIVE tag. # The default value is: NO. EXAMPLE_RECURSIVE = YES # The IMAGE_PATH tag can be used to specify one or more files or directories # that contain images that are to be included in the documentation (see the # \image command). IMAGE_PATH = @IGNITION_DOXYGEN_IMAGE_PATH@ # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command: # # # # where is the value of the INPUT_FILTER tag, and is the # name of an input file. Doxygen will then use the output that the filter # program writes to standard output. If FILTER_PATTERNS is specified, this tag # will be ignored. # # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the # filter if there is a match. The filters are a list of the form: pattern=filter # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. # # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. FILTER_PATTERNS = *.hh="sed -e 's/inline\snamespace\s.*\s{$\|ignition::@IGN_DESIGNATION@::\|IGN_DEPRECATED([0-9\.]\+)\|IGNITION_@IGN_DESIGNATION_UPPER@_VISIBLE//g'" # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will also be used to filter the input files that are used for # producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). # The default value is: NO. FILTER_SOURCE_FILES = NO # The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file # pattern. A pattern will override the setting for FILTER_PATTERN (if any) and # it is also possible to disable source filtering for a specific pattern using # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. USE_MDFILE_AS_MAINPAGE = @IGNITION_DOXYGEN_API_MAINPAGE_MD@ #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will be # generated. Documented entities will be cross-referenced with these sources. # # Note: To get rid of all source code in the generated output, make sure that # also VERBATIM_HEADERS is set to NO. # The default value is: NO. SOURCE_BROWSER = NO # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. # The default value is: NO. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any # special comment blocks from generated source code fragments. Normal C, C++ and # Fortran comments will always remain visible. # The default value is: YES. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented # function all documented functions referencing it will be listed. # The default value is: NO. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and # REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will # link to the documentation. # The default value is: YES. REFERENCES_LINK_SOURCE = YES # If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the # source code will show a tooltip with additional information such as prototype, # brief description and links to the definition and documentation. Since this # will make the HTML file larger and loading of large files a bit slower, you # can opt to disable this feature. # The default value is: YES. # This tag requires that the tag SOURCE_BROWSER is set to YES. SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system # (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global # - Enable SOURCE_BROWSER and USE_HTAGS in the config file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # # Doxygen will invoke htags (and that will in turn invoke gtags), so these # tools must be available from the command line (i.e. in the search path). # # The result: instead of the source browser generated by doxygen, the links to # source code will now point to the output of htags. # The default value is: NO. # This tag requires that the tag SOURCE_BROWSER is set to YES. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a # verbatim copy of the header file for each class for which an include is # specified. Set to NO to disable this. # See also: Section \class. # The default value is: YES. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all # compounds will be generated. Enable this if the project contains a lot of # classes, structs, unions or interfaces. # The default value is: YES. ALPHABETICAL_INDEX = YES # The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in # which the alphabetical index list will be split. # Minimum value: 1, maximum value: 20, default value: 5. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all classes will # be put under the same header in the alphabetical index. The IGNORE_PREFIX tag # can be used to specify a prefix (or a list of prefixes) that should be ignored # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output # The default value is: YES. GENERATE_HTML = @IGNITION_DOXYGEN_GENHTML@ # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of # it. # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_OUTPUT = html # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). # The default value is: .html. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a user-defined HTML header file for # each generated HTML page. If the tag is left blank doxygen will generate a # standard header. # # To get valid HTML the header file that includes any scripts and style sheets # that doxygen needs, which is dependent on the configuration options used (e.g. # the setting GENERATE_TREEVIEW). It is highly recommended to start with a # default header using # doxygen -w html new_header.html new_footer.html new_stylesheet.css # YourConfigFile # and then modify the file new_header.html. See also section "Doxygen usage" # for information on how to generate the default header that doxygen normally # uses. # Note: The header is subject to change so you typically have to regenerate the # default header when upgrading to a newer version of doxygen. For a description # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_HEADER = @IGNITION_CMAKE_DOXYGEN_DIR@/header.html # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard # footer. See HTML_HEADER for more information on how to generate a default # footer and what special commands can be used inside the footer. See also # section "Doxygen usage" for information on how to generate the default footer # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_FOOTER = @IGNITION_CMAKE_DOXYGEN_DIR@/footer.html # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of # the HTML output. If left blank doxygen will generate a default style sheet. # See also section "Doxygen usage" for information on how to generate the style # sheet that doxygen normally uses. # Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as # it is more robust and this tag (HTML_STYLESHEET) will in the future become # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets # created by doxygen. Using this option one can overrule certain style aspects. # This is preferred over using HTML_STYLESHEET since it does not replace the # standard style sheet and is therefore more robust against future updates. # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note # that these files will be copied to the base HTML output directory. Use the # $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these # files. In the HTML_STYLESHEET file, use the file name only. Also note that the # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_HUE = 13 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors # in the HTML output. For a value of 0 the output will use grayscales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_SAT = 76 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the # luminance component of the colors in the HTML output. Values below 100 # gradually make the output lighter, whereas values above 100 make the output # darker. The value divided by 100 is the actual gamma applied, so 80 represents # a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not # change the gamma. # Minimum value: 40, maximum value: 240, default value: 80. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this # to YES can help to show when doxygen was last run and thus if the # documentation is up to date. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via Javascript. If disabled, the navigation index will # consists of multiple levels of tabs that are statically embedded in every HTML # page. Disable this option to support browsers that do not have Javascript, # like the Qt help browser. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. # HTML_DYNAMIC_MENUS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to # such a level that at most the specified number of entries are visible (unless # a fully collapsed tree already exceeds this amount). So setting the number of # entries 1 will produce a full collapsed tree by default. 0 is a special value # representing an infinite number of entries and will result in a full expanded # tree by default. # Minimum value: 0, maximum value: 9999, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development # environment (see: https://developer.apple.com/tools/xcode/), introduced with # OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_DOCSET = NO # This tag determines the name of the docset feed. A documentation feed provides # an umbrella under which multiple documentation sets from a single provider # (such as a company or product suite) can be grouped. # The default value is: Doxygen generated docs. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_FEEDNAME = "Ignition @IGN_DESIGNATION_CAP@ API Documentation" # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_BUNDLE_ID = org.doxygen.Project # The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop # (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML # files are now used as the Windows 98 help format, and will replace the old # Windows help format (.hlp) on all Windows platforms in the future. Compressed # HTML files also contain an index, a table of contents, and you can search for # words in the documentation. The HTML workshop also contains a viewer for # compressed HTML files. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_HTMLHELP = NO # The CHM_FILE tag can be used to specify the file name of the resulting .chm # file. You can add a path in front of the file if the result should not be # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler (hhc.exe). If non-empty, # doxygen will try to run the HTML help compiler on the generated index.hhp. # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated # (YES) or that it should be included in the master .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. GENERATE_CHI = NO # The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated # (YES) or a normal table of contents (NO) in the .chm file. Furthermore it # enables the Previous and Next buttons. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members to # the table of contents of the HTML help documentation and to the tree view. # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help # (.qch) of the generated HTML documentation. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify # the file name of the resulting .qch file. The path specified is relative to # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace # (see: http://doc.qt.io/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual # Folders (see: http://doc.qt.io/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom # Filters (see: http://doc.qt.io/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://doc.qt.io/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # generated, together with the HTML files, they form an Eclipse help plugin. To # install this plugin and make it available under the help contents menu in # Eclipse, the contents of the directory containing the HTML and XML files needs # to be copied into the plugins directory of eclipse. The name of the directory # within the plugins directory should be the same as the ECLIPSE_DOC_ID value. # After copying Eclipse needs to be restarted before the help appears. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_ECLIPSEHELP = NO # A unique identifier for the Eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have this # name. Each documentation set should have its own identifier. # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. ECLIPSE_DOC_ID = org.doxygen.Project # If you want full control over the layout of the generated HTML pages it might # be necessary to disable the index and replace it with your own. The # DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top # of each HTML page. A value of NO enables the index and the value YES disables # it. Since the tabs in the index contain the same information as the navigation # tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. DISABLE_INDEX = YES # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. If the tag # value is set to YES, a side panel will be generated containing a tree-like # index structure (just like the one that is generated for HTML Help). For this # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can # further fine-tune the look of the index. As an example, the default style # sheet generated by doxygen has an example that shows how to put an image at # the root of the tree instead of the PROJECT_NAME. Since the tree basically has # the same information as the tab index, you could consider setting # DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # # Note that a value of 0 will completely suppress the enum values from appearing # in the overview section. # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. ENUM_VALUES_PER_LINE = 4 # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used # to set the initial width (in pixels) of the frame in which the tree is shown. # Minimum value: 0, maximum value: 1500, default value: 250. # This tag requires that the tag GENERATE_HTML is set to YES. TREEVIEW_WIDTH = 250 # If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to # external symbols imported via tag files in a separate window. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML # output directory to force them to be regenerated. # Minimum value: 8, maximum value: 50, default value: 10. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # # Note that when changing this option you need to delete any form_*.png files in # the HTML output directory before the changes have effect. # The default value is: YES. # This tag requires that the tag GENERATE_HTML is set to YES. FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see # https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path # to it using the MATHJAX_RELPATH option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: # http://docs.mathjax.org/en/latest/output.html) for more details. # Possible values are: HTML-CSS (which is slower, but has the best # compatibility), NativeMML (i.e. MathML) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_FORMAT = HTML-CSS # When MathJax is enabled you need to specify the location relative to the HTML # output directory using the MATHJAX_RELPATH option. The destination directory # should contain the MathJax.js script. For instance, if the mathjax directory # is located at the same level as the HTML output directory, then # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of # MathJax from https://www.mathjax.org before deployment. # The default value is: http://cdn.mathjax.org/mathjax/latest. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site # (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and # should work on any modern browser. Note that when using HTML help # (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) # there is already a search function so this one should typically be disabled. # For large projects the javascript based search engine can be slow, then # enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to # search using the keyboard; to jump to the search box use + S # (what the is depends on the OS and browser, but it is typically # , /