diff --git a/.codecov.yml b/.codecov.yml index c5fbf92f6..9b2262ed2 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -13,7 +13,7 @@ ignore: - "tools/*" - "python/**/*" - "mt-kahypar/definitions.h" - - "mt-kahypar/application/kahypar.cc" + - "mt-kahypar/application/mt_kahypar.cc" - "mt-kahypar/io/command_line_options.h" - "mt-kahypar/io/command_line_options.cpp" - "mt-kahypar/io/partitioning_output.h" diff --git a/.github/workflows/branch_ci.yml b/.github/workflows/branch_ci.yml index 28795d5f5..24a69baf6 100644 --- a/.github/workflows/branch_ci.yml +++ b/.github/workflows/branch_ci.yml @@ -11,78 +11,71 @@ jobs: strategy: matrix: compiler: [ { os: ubuntu-22.04, cpp: g++-11, cc: gcc-11, install_cmd: g++-11 gcc-11 }, + { os: ubuntu-24.04, cpp: g++-14, cc: gcc-14, install_cmd: g++-14 gcc-14 }, { os: ubuntu-22.04, cpp: clang++, cc: clang, install_cmd: clang } ] runs-on: ${{ matrix.compiler.os }} env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | sudo apt-get install libtbb-dev libboost-program-options-dev libhwloc-dev lcov gcovr ${{ matrix.compiler.install_cmd }} - - name: Install Mt-KaHyPar Test Suite + - name: Install Mt-KaHyPar env: CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cpp }} run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON -DKAHYPAR_ENABLE_SOED_METRIC=OFF -DKAHYPAR_ENABLE_STEINER_TREE_METRIC=OFF -DKAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES=OFF -DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=OFF -DKAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES=OFF + cmake .. --preset=minimal-dev -DKAHYPAR_CI_BUILD=ON make -j2 MtKaHyPar mt_kahypar_test_suite: name: Test Suite - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | - sudo apt-get install libtbb-dev libhwloc-dev libboost-program-options-dev lcov gcovr + sudo apt-get install libtbb-dev libhwloc-dev libboost-program-options-dev lcov gcovr g++-14 gcc-14 - name: Install Mt-KaHyPar Test Suite + env: + CC: gcc-14 + CXX: g++-14 run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_USE_GCOV=ON -DKAHYPAR_CI_BUILD=ON -DKAHYPAR_ENABLE_SOED_METRIC=OFF -DKAHYPAR_ENABLE_STEINER_TREE_METRIC=OFF -DKAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES=OFF -DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=OFF -DKAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES=OFF - make -j2 mt_kahypar_tests; + cmake .. --preset=minimal-dev -DKAHYPAR_USE_GCOV=ON -DKAHYPAR_CI_BUILD=ON + make -j2 mtkahypar_tests - name: Run Mt-KaHyPar Tests run: | cd build - ./tests/mt_kahypar_tests + ./tests/mtkahypar_tests mt_kahypar_c_interface_tests: name: C Interface Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -90,25 +83,21 @@ jobs: - name: Run Mt-KaHyPar C Library Interface Tests run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON - make -j2 interface_test + cmake .. --preset=dev -DKAHYPAR_CI_BUILD=ON + make -j2 mtkahypar_interface_test mt_kahypar_python_interface_tests: name: Python Interface Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -116,11 +105,10 @@ jobs: - name: Build Mt-KaHyPar Python Interface run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON + cmake .. --preset=python -DKAHYPAR_CI_BUILD=ON make mtkahypar_python -j2 - name: Run Mt-KaHyPar Python Interface Tests diff --git a/.github/workflows/master_ci.yml b/.github/workflows/master_ci.yml index 5d9e887e8..1168c0a7b 100644 --- a/.github/workflows/master_ci.yml +++ b/.github/workflows/master_ci.yml @@ -13,51 +13,72 @@ jobs: name: Ubuntu Build strategy: matrix: - compiler: [ { os: ubuntu-20.04, cpp: g++-9, cc: gcc-9, install_cmd: g++-9 gcc-9 }, - { os: ubuntu-20.04, cpp: g++-10, cc: gcc-10, install_cmd: g++-10 gcc-10 }, - { os: ubuntu-22.04, cpp: g++-11, cc: gcc-11, install_cmd: g++-11 gcc-11 }, - { os: ubuntu-22.04, cpp: g++-12, cc: gcc-12, install_cmd: g++-12 gcc-12 }, - { os: ubuntu-22.04, cpp: clang++, cc: clang, install_cmd: clang } ] + compiler: [ { os: ubuntu-22.04, cpp: g++-11, cc: gcc-11, install_cmd: g++-11 gcc-11 }, + { os: ubuntu-24.04, cpp: g++-14, cc: gcc-14, install_cmd: g++-14 gcc-14 }, + { os: ubuntu-24.04, cpp: clang++, cc: clang, install_cmd: clang } ] runs-on: ${{ matrix.compiler.os }} env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | sudo apt-get install libtbb-dev libboost-program-options-dev libhwloc-dev lcov gcovr ${{ matrix.compiler.install_cmd }} - - name: Install Mt-KaHyPar Test Suite + - name: Install Mt-KaHyPar env: CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cpp }} run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON + cmake .. --preset=default -DKAHYPAR_CI_BUILD=ON + make -j2 MtKaHyPar + + mt_kahypar_static_build: + name: Statically Linked Build + runs-on: ubuntu-24.04 + env: + CI_ACTIVE : 1 + + steps: + - name: Checkout HEAD + uses: actions/checkout@v4 + + - name: Install Dependencies + run: | + sudo apt-get install libtbb-dev libboost-program-options-dev libhwloc-dev libudev-dev + + - name: Install Mt-KaHyPar + run: | + rm -rf build + mkdir build + cd build + cmake .. --preset=minimal -DKAHYPAR_CI_BUILD=ON -DBUILD_SHARED_LIBS=OFF -DKAHYPAR_STATIC_LINK_DEPENDENCIES=ON make -j2 MtKaHyPar + if [[ $(ldd mt-kahypar/application/MtKaHyPar | grep hwloc) ]]; then + echo "Error: hwloc is dynamically linked" + exit 1 + fi + if [[ $(ldd mt-kahypar/application/MtKaHyPar | grep boost) ]]; then + echo "Error: boost is dynamically linked" + exit 1 + fi mt_kahypar_test_suite: name: Test Suite - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 # note: stay on 22.04 since lcov behaves weird on 24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -65,40 +86,36 @@ jobs: - name: Install Mt-KaHyPar Test Suite run: | - git submodule update --init --recursive - rm -rf debug - mkdir debug - cd debug - cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DKAHYPAR_USE_GCOV=ON -DKAHYPAR_CI_BUILD=ON - make -j2 mt_kahypar_tests; + rm -rf build + mkdir build + cd build + cmake .. --preset=dev -DCMAKE_BUILD_TYPE=DEBUG -DKAHYPAR_CI_BUILD=ON -DKAHYPAR_USE_GCOV=ON + make -j2 mtkahypar_tests - name: Run Mt-KaHyPar Tests run: | - cd debug - ./tests/mt_kahypar_tests; + cd build + ./tests/mtkahypar_tests - name: Report Code Coverage run: | - cd debug - lcov --directory . --capture --output-file coverage.info; - lcov --remove coverage.info '/usr/*' --output-file coverage.info; - lcov --list coverage.info; - gcovr -r ../ -x > report.xml; + cd build + lcov --directory . --capture --output-file coverage.info --exclude '**/external_tools/**/*' --exclude '**/tests/**/*' --exclude '**/googletest-src/**/*' + lcov --remove coverage.info '/usr/**/*' '**/external_tools/**/*' '**/tests/**/*' --output-file coverage.info + lcov --list coverage.info + gcovr -r ../ -x > report.xml cd .. bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" mt_kahypar_integration_tests: name: Integration Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -106,11 +123,10 @@ jobs: - name: Install Mt-KaHyPar Integration Tests run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON + cmake .. --preset=python -DKAHYPAR_CI_BUILD=ON make -j2 MtKaHyPar make -j2 VerifyPartition make -j2 GridGraphGenerator @@ -122,16 +138,13 @@ jobs: mt_kahypar_c_interface_tests: name: C Interface Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -139,25 +152,21 @@ jobs: - name: Run Mt-KaHyPar C Library Interface Tests run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON - make -j2 interface_test + cmake .. --preset=dev -DKAHYPAR_CI_BUILD=ON + make -j2 mtkahypar_interface_test mt_kahypar_python_interface_tests: name: Python Interface Tests - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 env: - BOOST_ROOT : "/usr/local/share/boost/1.72.0" CI_ACTIVE : 1 steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -165,11 +174,10 @@ jobs: - name: Build Mt-KaHyPar Python Interface run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON + cmake .. --preset=python -DKAHYPAR_CI_BUILD=ON make mtkahypar_python -j2 - name: Run Mt-KaHyPar Python Interface Tests @@ -186,9 +194,7 @@ jobs: steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Setup MSYS2 uses: msys2/setup-msys2@v2 @@ -204,26 +210,21 @@ jobs: run: | echo "${{ runner.temp }}/msys64/mingw64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Rename TBB library file - run: | - Ren ${{ runner.temp }}/msys64/mingw64/lib/libtbb12.dll.a ${{ runner.temp }}/msys64/mingw64/lib/libtbb.dll.a - - name: Install Mt-KaHyPar Multilevel Tests shell: msys2 {0} run: | - git submodule update --init --recursive rm -rf build mkdir build cd build export CMAKE_GENERATOR="MSYS Makefiles" - /mingw64/bin/cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON -DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=OFF -DKAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES=OFF - make -j2 mt_kahypar_tests + /mingw64/bin/cmake .. --preset=dev -DKAHYPAR_CI_BUILD=ON -DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=OFF -DKAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES=OFF + make -j2 mtkahypar_tests - name: Run Mt-KaHyPar Tests shell: msys2 {0} run: | cd build - ./tests/mt_kahypar_tests + ./tests/mtkahypar_tests mt_kahypar_macos_build: name: MacOS Build @@ -233,9 +234,7 @@ jobs: steps: - name: Checkout HEAD - uses: actions/checkout@v3 - with: - fetch-depth: 1 + uses: actions/checkout@v4 - name: Install Dependencies run: | @@ -243,14 +242,13 @@ jobs: - name: Install Mt-KaHyPar Multilevel Tests run: | - git submodule update --init --recursive rm -rf build mkdir build cd build - cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DKAHYPAR_CI_BUILD=ON - make -j2 mt_kahypar_tests + cmake .. --preset=dev -DKAHYPAR_CI_BUILD=ON + make -j2 mtkahypar_tests - name: Run Mt-KaHyPar Tests run: | cd build - ./tests/mt_kahypar_tests + ./tests/mtkahypar_tests diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 2399c102f..000000000 --- a/.gitmodules +++ /dev/null @@ -1,15 +0,0 @@ -[submodule "external_tools/googletest"] - path = external_tools/googletest - url = https://github.com/google/googletest.git -[submodule "external_tools/WHFC"] - path = external_tools/WHFC - url = https://github.com/larsgottesbueren/WHFC.git -[submodule "python/pybind11"] - path = python/pybind11 - url = https://github.com/pybind/pybind11.git -[submodule "external_tools/growt"] - path = external_tools/growt - url = https://github.com/TooBiased/growt.git -[submodule "external_tools/kahypar-shared-resources"] - path = external_tools/kahypar-shared-resources - url = https://github.com/kahypar/kahypar-shared-resources.git diff --git a/CMakeLists.txt b/CMakeLists.txt index c360fe82e..62b55d3ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,431 +1,510 @@ -cmake_minimum_required(VERSION 3.16) +cmake_minimum_required(VERSION 3.26) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) -project(MtKaHyPar CXX C) -set(PROJECT_VENDOR "Tobias Heuer") -set(PROJECT_CONTACT "tobias.heuer@kit.edu") -set(PROJECT_URL "https://github.com/kittobi1992/mt-kahypar") -set(PROJECT_DESCRIPTION "Mt-KaHyPar: Multi-Threaded Karlsruhe Hypergraph Partitioning") -set(PROJECT_VERSION "1.0.0") -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# define the project version +set(MT_KAHYPAR_VERSION "1.5") +string(SUBSTRING "${MT_KAHYPAR_VERSION}" 0 1 MT_KAHYPAR_SO_VERSION) +set(MTKAHYPAR_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") -# CMake Options +project(MtKaHyPar + VERSION ${MT_KAHYPAR_VERSION} + DESCRIPTION "Mt-KaHyPar: Multi-Threaded Karlsruhe Hypergraph Partitioning" + LANGUAGES CXX C) +set(PROJECT_URL "https://github.com/kahypar/mt-kahypar") -option(KAHYPAR_DOWNLOAD_BOOST - "Download boost automatically and compile required libraries." OFF) -option(KAHYPAR_DOWNLOAD_TBB - "Download TBB automatically." OFF) +################################################################# +## Sanity checks and policies ## +################################################################# -option(KAHYPAR_ENFORCE_MINIMUM_TBB_VERSION - "Enforces the minimum required TBB version." ON) - -option(KAHYPAR_USE_GCOV - "Compile and run tests with gcov for coverage analysis." OFF) - -option(KAHYPAR_DISABLE_ASSERTIONS - "Disable KaHyPar's internal assertions." OFF) - -option(KAHYPAR_USE_STANDARD_ASSERTIONS - "Use standard C++ asserts instead of custom assertions." OFF) - -option(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS - "Enable heavy assertions in preprocessing phase." OFF) - -option(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS - "Enable heavy assertions in coarsening phase." OFF) - -option(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS - "Enable heavy assertions in initial partitioning phase." OFF) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "RelWithDebInfo") + message(FATAL_ERROR "CMAKE_BUILD_TYPE must be set. Options are: Debug, Release, RelWithDebInfo") +endif() +if("${PROJECT_SOURCE_DIR}" STREQUAL "${PROJECT_BINARY_DIR}") + message(FATAL_ERROR "Build directory must be different from source directory.") +endif() +if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") + message(FATAL_ERROR "MSVC not supported at the moment") +endif() -option(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS - "Enable heavy assertions in refinement phase." OFF) +if (POLICY CMP0135) # download timestamps + cmake_policy(SET CMP0135 NEW) +endif() +if (POLICY CMP0144) # uppercase find_package variables + cmake_policy(SET CMP0144 NEW) +endif() +if (POLICY CMP0167) # new FindBoost behavior + cmake_policy(SET CMP0167 NEW) +endif() -option(KAHYPAR_USE_64_BIT_IDS - "Enables 64-bit vertex and hyperedge IDs." OFF) +if (NOT DEFINED BUILD_SHARED_LIBS AND NOT WIN32) + # since TBB does not support static linking, we build with dynamic linking by default (except on Windows) + set(BUILD_SHARED_LIBS ON) +endif() -option(KAHYPAR_TRAVIS_BUILD - "Indicate that this build is executed on Travis CI." OFF) +################################################################# +## Meta targets ## +################################################################# + +# meta targets for flags +add_library(MtKaHyPar-BuildFlags INTERFACE) +target_compile_features(MtKaHyPar-BuildFlags INTERFACE cxx_std_17) + +# meta targets for includes and source files +add_library(MtKaHyPar-Include INTERFACE) +target_include_directories(MtKaHyPar-Include INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(MtKaHyPar-Sources INTERFACE) + +add_library(MtKaHyPar-ToolsSources INTERFACE) + +# meta target for CLI/test build +add_library(MtKaHyPar-BuildSources OBJECT "") +target_link_libraries(MtKaHyPar-BuildSources PRIVATE MtKaHyPar-Sources) +target_link_libraries(MtKaHyPar-BuildSources PUBLIC MtKaHyPar-Include MtKaHyPar-BuildFlags) + +# meta target for library build, which must be built with all features enabled +add_library(MtKaHyPar-LibraryBuildSources OBJECT "") +target_link_libraries(MtKaHyPar-LibraryBuildSources PRIVATE MtKaHyPar-Sources) +target_link_libraries(MtKaHyPar-LibraryBuildSources PUBLIC MtKaHyPar-Include MtKaHyPar-BuildFlags) +target_compile_definitions(MtKaHyPar-LibraryBuildSources PUBLIC MT_KAHYPAR_LIBRARY_MODE + KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES + KAHYPAR_ENABLE_SOED_METRIC KAHYPAR_ENABLE_STEINER_TREE_METRIC) +# building shared libraries requires position independent code +if(BUILD_SHARED_LIBS) + set_target_properties(MtKaHyPar-LibraryBuildSources PROPERTIES POSITION_INDEPENDENT_CODE ON) +endif() -option(KAHYPAR_CI_BUILD - "Indicate that this build is executed on GitHub Actions." OFF) -option(KAHYPAR_ADD_ADDRESS_SANITIZER - "Adds address sanitizer to compile options." ON) +################################################################# +## Options ## +################################################################# + +# general build options +option(KAHYPAR_PYTHON "Include the Python interface in the build." OFF) +option(KAHYPAR_ENABLE_TESTING "Enables tests, which requires dowloading googletest." OFF) +option(KAHYPAR_STATIC_LINK_DEPENDENCIES "In static build, also link dependencies (other than TBB) statically." OFF) +option(KAHYPAR_STATIC_LINK_TBB "In static build, also link TBB statically. Note that this is not officially supported!" OFF) +option(KAHYPAR_INSTALL_CLI "Provide a target to install an executable binary `mtkahypar`." OFF) + +# dependencies +option(KAHYPAR_DOWNLOAD_BOOST "Download boost automatically and compile required libraries." OFF) +option(KAHYPAR_DOWNLOAD_TBB "Download TBB automatically." OFF) +option(KAHYPAR_DISABLE_HWLOC "Exclude components requiring hwloc. Might impact performance on NUMA platforms." OFF) + +# specific compile features/build properties +option(KAHYPAR_USE_64_BIT_IDS "Enables 64-bit vertex and hyperedge IDs." OFF) +option(KAHYPAR_USE_ADDRESS_SANITIZER "Adds address sanitizer to compile options." OFF) +option(KAHYPAR_ENABLE_EXTENDED_INSTRUCTIONS "Allows instructions that might not be fully portable: `-mcx16 -msse4.2 -mcrc32`" OFF) +option(KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS "Adds the compile flags `-mtune=native -march=native`" OFF) +option(KAHYPAR_ENABLE_THREAD_PINNING "Enables thread pinning in Mt-KaHyPar." OFF) + +# algorithm features for CLI build (note: the library always contains all non-experimental features) +option(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES "Enables graph partitioning features. Can be turned off for faster compilation." OFF) +option(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES "Enables highest quality preset features. Can be turned off for faster compilation." OFF) +option(KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES "Enables large k partitioning features. Can be turned off for faster compilation." OFF) +option(KAHYPAR_ENABLE_SOED_METRIC "Enables the sum-of-external-degree metric. Can be turned off for faster compilation." OFF) +option(KAHYPAR_ENABLE_STEINER_TREE_METRIC "Enables the Steiner tree metric. Can be turned off for faster compilation." OFF) +option(KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES "Enables some experimental features. Can be turned off for faster compilation." OFF) + +# assertions +option(KAHYPAR_DISABLE_ASSERTIONS "Disable all internal assertions." OFF) +option(KAHYPAR_USE_STANDARD_ASSERTIONS "Use standard C++ asserts instead of custom assertions." OFF) +option(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS "Enable heavy assertions in preprocessing phase." OFF) +option(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS "Enable heavy assertions in coarsening phase." OFF) +option(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS "Enable heavy assertions in initial partitioning phase." OFF) +option(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS "Enable heavy assertions in refinement phase." OFF) + +# developer build options +option(KAHYPAR_CI_BUILD "Indicate that this build is executed on GitHub Actions." OFF) +option(KAHYPAR_USE_GCOV "Compile and run tests with gcov for coverage analysis." OFF) -option(KAHYPAR_ENABLE_THREAD_PINNING - "Enables thread pinning in Mt-KaHyPar." ON) -option(KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS - "Adds the compile flags `-mtune=native -march=native`" ON) +if(KAHYPAR_ENABLE_STEINER_TREE_METRIC AND NOT KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) + message(FATAL_ERROR "Steiner tree metric requires graph features. Add -DKAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES=On to your cmake command") +endif() -option(KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES - "Enables some experimental features. Can be turned off for faster compilation." OFF) -option(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES - "Enables graph partitioning features. Can be turned off for faster compilation." ON) +################################################################# +## Print header with most important infos ## +################################################################# -option(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - "Enables highest quality preset features. Can be turned off for faster compilation." ON) +if(CMAKE_BUILD_TYPE) + # normalize so that exactly the first letter is uppercase + string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_UPPER) + string(TOLOWER "${CMAKE_BUILD_TYPE}" BUILD_TYPE_LOWER) + string(SUBSTRING "${BUILD_TYPE_UPPER}" 0 1 FIRST_LETTER) + string(SUBSTRING "${BUILD_TYPE_LOWER}" 1 -1 REMAINDER) + set(KAHYPAR_BUILD_DESCRIPTION "${FIRST_LETTER}${REMAINDER} Build") + if (KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS AND NOT BUILD_TYPE_UPPER MATCHES "DEBUG") + set(KAHYPAR_BUILD_DESCRIPTION "${KAHYPAR_BUILD_DESCRIPTION} + march=native") + endif() + if(KAHYPAR_ENABLE_TESTING) + set(KAHYPAR_TESTING_ENABLED "Enabled") + else() + set(KAHYPAR_TESTING_ENABLED "Disabled") + endif() + if(BUILD_SHARED_LIBS) + set(KAHYPAR_LINKING_TYPE "Dynamic") + else() + set(KAHYPAR_LINKING_TYPE "Static") + endif() + message(STATUS "Mt-KaHyPar: ${KAHYPAR_BUILD_DESCRIPTION}, Tests ${KAHYPAR_TESTING_ENABLED}, ${KAHYPAR_LINKING_TYPE} Linking") +endif() -option(KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES - "Enables large k partitioning features. Can be turned off for faster compilation." ON) -option(KAHYPAR_ENABLE_SOED_METRIC - "Enables the sum-of-external-degree metric. Can be turned off for faster compilation." ON) +################################################################# +## Compatibility checks which interact with options ## +################################################################# -option(KAHYPAR_ENABLE_STEINER_TREE_METRIC - "Enables the Steiner tree metric. Can be turned off for faster compilation." ON) +if(KAHYPAR_ENABLE_THREAD_PINNING AND KAHYPAR_DISABLE_HWLOC) + message(WARNING "Thread pinning disabled since hwloc library is disabled.") + set(KAHYPAR_ENABLE_THREAD_PINNING FALSE CACHE STRING "" FORCE) +endif() -option(KAHYPAR_PYTHON - "Build the Python interface. Can be turned off in case Python is not available." ON) +if(UNIX) + include(CheckIncludeFiles) + set(CMAKE_REQUIRED_QUIET TRUE) + set(KAHYPAR_REQUIRED_HEADERS "unistd.h" "sys/mman.h" "sys/ioctl.h") + check_include_files("${KAHYPAR_REQUIRED_HEADERS}" KAHYPAR_HEADERS_AVAILABLE LANGUAGE CXX) + if(NOT KAHYPAR_HEADERS_AVAILABLE) + message(FATAL_ERROR "The following system headers are required, but some are not available: ${KAHYPAR_REQUIRED_HEADERS}") + endif() -option(MT_KAHYPAR_DISABLE_BOOST - "Whether to exclude components requiring Boost::program_options. Will result in no binary target and the C and Python interface not being able to load configuration files." OFF) + include(CheckThreadPinning) + if(KAHYPAR_ENABLE_THREAD_PINNING AND NOT THREAD_PINNING_WORKS) + message(WARNING "Thread pinning disabled since required system APIs are not available.") + set(KAHYPAR_ENABLE_THREAD_PINNING FALSE CACHE STRING "" FORCE) + endif() +elseif(NOT WIN32) + message(FATAL_ERROR "Only unix-based operating systems and windows are supported.") +endif() -if(KAHYPAR_ENABLE_STEINER_TREE_METRIC AND NOT KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) - message(FATAL_ERROR "Steiner tree metric requires graph features. Add -DKAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES=On to your cmake command") -endif() +################################################################# +## Options that translate into compile flags ## +################################################################# if(KAHYPAR_DISABLE_ASSERTIONS) - add_compile_definitions(KAHYPAR_DISABLE_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_DISABLE_ASSERTIONS) endif(KAHYPAR_DISABLE_ASSERTIONS) if(KAHYPAR_USE_STANDARD_ASSERTIONS) - add_compile_definitions(KAHYPAR_USE_STANDARD_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_USE_STANDARD_ASSERTIONS) endif(KAHYPAR_USE_STANDARD_ASSERTIONS) if(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS) - add_compile_definitions(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS) endif(KAHYPAR_ENABLE_HEAVY_PREPROCESSING_ASSERTIONS) if(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS) - add_compile_definitions(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS) endif(KAHYPAR_ENABLE_HEAVY_COARSENING_ASSERTIONS) if(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS) - add_compile_definitions(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS) endif(KAHYPAR_ENABLE_HEAVY_INITIAL_PARTITIONING_ASSERTIONS) if(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS) - add_compile_definitions(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS) endif(KAHYPAR_ENABLE_HEAVY_REFINEMENT_ASSERTIONS) if(KAHYPAR_USE_64_BIT_IDS) - add_compile_definitions(KAHYPAR_USE_64_BIT_IDS) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_USE_64_BIT_IDS) endif(KAHYPAR_USE_64_BIT_IDS) -if(KAHYPAR_TRAVIS_BUILD) - add_compile_definitions(KAHYPAR_TRAVIS_BUILD) -endif(KAHYPAR_TRAVIS_BUILD) - if(KAHYPAR_ENABLE_THREAD_PINNING) - add_compile_definitions(KAHYPAR_ENABLE_THREAD_PINNING) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_THREAD_PINNING) endif(KAHYPAR_ENABLE_THREAD_PINNING) if(KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES) - add_compile_definitions(KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES) endif(KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES) if(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) - add_compile_definitions(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) endif(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) if(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) - add_compile_definitions(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) endif(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) if(KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) - add_compile_definitions(KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) endif(KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) if(KAHYPAR_ENABLE_SOED_METRIC) - add_compile_definitions(KAHYPAR_ENABLE_SOED_METRIC) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_SOED_METRIC) endif(KAHYPAR_ENABLE_SOED_METRIC) if(KAHYPAR_ENABLE_STEINER_TREE_METRIC) - add_compile_definitions(KAHYPAR_ENABLE_STEINER_TREE_METRIC) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_ENABLE_STEINER_TREE_METRIC) endif(KAHYPAR_ENABLE_STEINER_TREE_METRIC) -if(MT_KAHYPAR_DISABLE_BOOST) - add_compile_definitions(MT_KAHYPAR_DISABLE_BOOST) +if(KAHYPAR_DISABLE_HWLOC) + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_DISABLE_HWLOC) endif() -include_directories(${PROJECT_SOURCE_DIR}) -find_package(Threads REQUIRED) -message(STATUS "Found Threads: ${CMAKE_THREAD_LIBS_INIT}") - -# Include Submodules -add_subdirectory(external_tools/googletest EXCLUDE_FROM_ALL) -include_directories(SYSTEM ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) -include_directories(SYSTEM ${gtest_SOURCE_DIR}/../googlemock/include ${gtest_SOURCE_DIR}/../googlemock/) -include_directories(external_tools/kahypar-shared-resources) -include_directories(external_tools/growt) -include_directories(external_tools/WHFC) -include_directories(external_tools/pcg) - -if(KAHYPAR_DOWNLOAD_BOOST) - # Download Boost - execute_process(COMMAND cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/scripts/download_boost.cmake) - include_directories(SYSTEM ${CMAKE_CURRENT_BINARY_DIR}/external_tools/boost/) - file(GLOB MINI_BOOST_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/external_tools/boost/libs/program_options/src/*.cpp) - - add_library(mini_boost STATIC ${MINI_BOOST_SOURCES}) - set_target_properties(mini_boost PROPERTIES LINKER_LANGUAGE CXX) - set(Boost_LIBRARIES mini_boost) - set(Boost_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/external_tools/boost/boost/) - include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) -else() - # Find Boost Program Options Library - find_package(Boost 1.69 REQUIRED COMPONENTS program_options) - if(Boost_FOUND) - include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) - set(KAHYPAR_INCLUDE_DIRS ${Boost_INCLUDE_DIRS} ${KAHYPAR_INCLUDE_DIRS}) - set(KAHYPAR_LINK_LIBRARIES ${Boost_LIBRARIES} ${KAHYPAR_LINK_LIBRARIES}) - message(STATUS "Boost Include: ${Boost_INCLUDE_DIRS}") - message(STATUS "Boost Library Dirs: ${Boost_LIBRARY_DIRS}") - message(STATUS "Boost Libraries: ${Boost_LIBRARIES}") - if(WIN32) - add_definitions(-DBOOST_ALL_NO_LIB) - add_definitions(-DBOOST_PROGRAM_OPTIONS_DYN_LINK=1) - endif() + +################################################################# +## Setup of dependencies ## +################################################################# + +include(FetchContent) +set(KAHYPAR_SHARED_RESOURCES_TAG 6d5c8e2444e4310667ec1925e995f26179d7ee88) +set(KAHYPAR_WHFC_TAG 5ae2e3664391ca0db7fab2c82973e98c48937a08) +set(KAHYPAR_GROWT_TAG 0c1148ebcdfd4c04803be79706533ad09cc81d37) +set(KAHYPAR_TBB_VERSION v2022.0.0) +set(KAHYPAR_GOOGLETEST_VERSION v1.15.2) +set(KAHYPAR_PYBIND11_VERSION v2.13.6) + +message(STATUS "Fetching dependencies...") + +# Include header-only dependencies +FetchContent_Populate( + kahypar-shared-resources QUIET EXLUDE_FROM_ALL + GIT_REPOSITORY https://github.com/kahypar/kahypar-shared-resources.git + GIT_TAG ${KAHYPAR_SHARED_RESOURCES_TAG} + SOURCE_DIR external_tools/kahypar-shared-resources +) +FetchContent_Populate( + WHFC QUIET EXLUDE_FROM_ALL + GIT_REPOSITORY https://github.com/larsgottesbueren/WHFC.git + GIT_TAG ${KAHYPAR_WHFC_TAG} + SOURCE_DIR external_tools/WHFC +) +FetchContent_Populate( + growt QUIET EXLUDE_FROM_ALL + GIT_REPOSITORY https://github.com/TooBiased/growt.git + GIT_TAG ${KAHYPAR_GROWT_TAG} + SOURCE_DIR external_tools/growt +) + +target_include_directories(MtKaHyPar-Include INTERFACE + ${CMAKE_CURRENT_BINARY_DIR}/external_tools/kahypar-shared-resources + ${CMAKE_CURRENT_BINARY_DIR}/external_tools/growt + ${CMAKE_CURRENT_BINARY_DIR}/external_tools/WHFC) + + +if (KAHYPAR_ENABLE_TESTING) + FetchContent_Declare( + googletest EXCLUDE_FROM_ALL SYSTEM + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG ${KAHYPAR_GOOGLETEST_VERSION} + ) + FetchContent_MakeAvailable(googletest) + include(gmock) + enable_testing() + + add_library(MtKaHyPar-Test INTERFACE) + target_link_libraries(MtKaHyPar-Test INTERFACE gmock gtest gtest_main) +endif() + +# check for linking problems +if(BUILD_SHARED_LIBS AND KAHYPAR_STATIC_LINK_DEPENDENCIES) + if(NOT KAHYPAR_DOWNLOAD_BOOST OR NOT CMAKE_POSITION_INDEPENDENT_CODE) + message(WARNING "Building a shared lib with static linking of transitive dependencies requires building Boost from source with -DCMAKE_POSITION_INDEPENDENT_CODE=On") + endif() +endif() + +block() + if(KAHYPAR_STATIC_LINK_DEPENDENCIES) + set(Boost_USE_STATIC_LIBS ON) + set(BUILD_SHARED_LIBS OFF) + endif() + if(KAHYPAR_DOWNLOAD_BOOST) + # Download Boost + set(BOOST_INCLUDE_LIBRARIES program_options range dynamic_bitset) + set(BOOST_ENABLE_CMAKE ON) + FetchContent_Declare( + Boost EXCLUDE_FROM_ALL SYSTEM + URL https://github.com/boostorg/boost/releases/download/boost-1.86.0/boost-1.86.0-cmake.tar.gz + ) + FetchContent_MakeAvailable(Boost) else() - MESSAGE(FATAL_ERROR " - Boost not found. Install Boost on your system or - add -DKAHYPAR_DOWNLOAD_BOOST=On to the cmake build command.") + # Find system Boost + find_package(Boost 1.69 REQUIRED COMPONENTS program_options) + if(NOT Boost_FOUND) + message(FATAL_ERROR " + Boost not found. Install Boost on your system or + add -DKAHYPAR_DOWNLOAD_BOOST=On to the cmake build command.") + endif() + message(STATUS "Boost Include: ${Boost_INCLUDE_DIRS}, Boost Library: ${Boost_LIBRARY_DIRS}") endif() +endblock() + +# the downloaded (newer) boost requires to add these targets explicitly +if(TARGET Boost::range) + target_link_libraries(MtKaHyPar-Include INTERFACE Boost::range) +endif() +if(TARGET Boost::dynamic_bitset) + target_link_libraries(MtKaHyPar-Include INTERFACE Boost::dynamic_bitset) endif() +target_link_libraries(MtKaHyPar-Include INTERFACE Boost::program_options) + -# Download TBB if(KAHYPAR_DOWNLOAD_TBB) - if ( UNIX AND NOT WIN32 ) - execute_process(COMMAND cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/scripts/download_tbb_linux.cmake) - set(TBB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/external_tools/tbb) - elseif ( MSVC ) - execute_process(COMMAND cmake -G ${CMAKE_GENERATOR} -P ${CMAKE_CURRENT_SOURCE_DIR}/scripts/download_tbb_windows.cmake) - set(TBB_ROOT ${CMAKE_CURRENT_BINARY_DIR}/external_tools/tbb) - else() - MESSAGE(WARNING " - We did not find a TBB version for your platform online. - The build uses the TBB version installed on your system.") + # Download TBB library + FetchContent_Declare( + TBB EXCLUDE_FROM_ALL SYSTEM + GIT_REPOSITORY https://github.com/oneapi-src/oneTBB.git + GIT_TAG ${KAHYPAR_TBB_VERSION} + GIT_SHALLOW FALSE # TBB seems to assume that a git repo is present + ) + block() + if(KAHYPAR_STATIC_LINK_TBB) + set(BUILD_SHARED_LIBS OFF) + else() + set(BUILD_SHARED_LIBS ON) + endif() + FetchContent_MakeAvailable(TBB) + endblock() +else() + # Find system TBB library + find_package(TBB 2021.5 COMPONENTS tbb tbbmalloc) + if(NOT TBB_FOUND) + message(FATAL_ERROR " + TBB library not found or current TBB version is too old. Install TBB on your system + or add -DKAHYPAR_DOWNLOAD_TBB=On to the cmake build command.") endif() + get_target_property(KAHYPAR_TBB_INCLUDE_DIRS TBB::tbb INTERFACE_INCLUDE_DIRECTORIES) + message(STATUS "TBB Version: ${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}, TBB Include: ${KAHYPAR_TBB_INCLUDE_DIRS}") endif() +target_link_libraries(MtKaHyPar-Include INTERFACE TBB::tbb TBB::tbbmalloc) -# Find TBB Library -find_package(TBB REQUIRED) -if (TBB_FOUND) - if ((TBB_INTERFACE_VERSION GREATER_EQUAL 12050) OR (NOT KAHYPAR_ENFORCE_MINIMUM_TBB_VERSION) OR KAHYPAR_CI_BUILD) - include_directories(SYSTEM ${TBB_INCLUDE_DIRS} ${TBB_MALLOC_INCLUDE_DIRS}) - link_libraries(${TBB_LIBRARIES} ${TBB_MALLOC_LIBRARIES}) - MESSAGE(STATUS "TBB Version: ${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR} (Interface Version=${TBB_INTERFACE_VERSION})") - MESSAGE(STATUS "Found TBB library: inc=${TBB_INCLUDE_DIRS}, lib=${TBB_LIBRARIES}") - MESSAGE(STATUS "Found TBB Malloc Proxy library: inc=${TBB_MALLOC_PROXY_INCLUDE_DIRS}, lib=${TBB_MALLOC_PROXY_LIBRARIES}") - ELSE () - MESSAGE(FATAL_ERROR " - Your current TBB version is too old. Your interface version is ${TBB_INTERFACE_VERSION}, but the minimum - required version is 12050 (OneTBB 2021.5). You can download a suitable version by adding - -DKAHYPAR_DOWNLOAD_TBB=ON to the cmake build command (may require to clear the cmake cache). - Note that Mt-KaHyPar also compiles with older versions of TBB. However, we found some unexpected - behavior of a TBB function that causes on our side segmentation faults in really rare cases. - If you want to ignore these warnings, you can add -DKAHYPAR_ENFORCE_MINIMUM_TBB_VERSION=OFF to the - cmake build command which will build Mt-KaHyPar with your current TBB version.") - ENDIF() -ELSE () - MESSAGE(FATAL_ERROR " - TBB library not found. Install TBB on your system or - add -DKAHYPAR_DOWNLOAD_TBB=On to the cmake build command - (only available for Linux and MSVC).") -ENDIF() # Find HWLOC Library -FIND_PATH(HWLOCK_INCLUDE_DIR NAME hwloc.h - HINTS $ENV{HOME}/local/include /opt/local/include /usr/local/include /usr/include) -FIND_LIBRARY(HWLOCK_LIBRARY NAME hwloc - HINTS $ENV{HOME}/local/lib64 $ENV{HOME}/local/lib /usr/local/lib64 /usr/local/lib /opt/local/lib64 /opt/local/lib /usr/lib64 /usr/lib -) - -IF (HWLOCK_INCLUDE_DIR AND HWLOCK_LIBRARY) - MESSAGE(STATUS "Found hwlock library: inc=${HWLOCK_INCLUDE_DIR}, lib=${HWLOCK_LIBRARY}") - include_directories(${HWLOCK_INCLUDE_DIR}) - link_libraries(${HWLOCK_LIBRARY}) -ELSE () - MESSAGE(FATAL_ERROR " - HwLoc library not found. Install HwLoc on your system.") -ENDIF () +if(NOT KAHYPAR_DISABLE_HWLOC) + include(DetectHwloc) + if(NOT TARGET HWLOC::hwloc) + message(FATAL_ERROR "Hwloc library not found. Install hwloc on your system.") + endif() + target_link_libraries(MtKaHyPar-Include INTERFACE HWLOC::hwloc) +endif() -# Add targets for code coverage analysis -if(KAHYPAR_USE_GCOV) - include(CodeCoverage) - setup_target_for_coverage(${PROJECT_NAME}_coverage tests coverage) +################################################################# +## Compile options and specialized builds ## +################################################################# - # find programs - find_program(GENHTML genhtml) - find_program(LCOV lcov) +if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") + set(KAHYPAR_X86 TRUE) +else() + set(KAHYPAR_X86 FALSE) +endif() - if(NOT LCOV OR NOT GENHTML) - message(SEND_ERROR "Coverage analysis requires lcov and genhtml.") - endif() +# Add compile flags that enable warnings +target_compile_options(MtKaHyPar-BuildFlags INTERFACE + -W -Wall -Wextra -Wunused -Wuninitialized -Wfatal-errors -Wcast-qual -Woverloaded-virtual + -Wredundant-decls -Wno-unused-function -Winit-self -pedantic -DPARANOID -Wno-unused-function) +if(KAHYPAR_USE_GCOV) # add coverage anaylsis compile and link flags - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") - - # add cached variable containing parameters for lcov/genhtml - set(LCOV_FLAGS "" CACHE STRING "parameters for lcov") - set(GENHTML_FLAGS --legend --no-branch-coverage - CACHE STRING "parameters for genhtml") - set(COVERAGE_LCOV_EXCLUDES "external_tools/*" ) - - # custom target to run before tests - add_custom_target(lcov-reset - COMMAND ${LCOV} -q --directory ${CMAKE_BINARY_DIR} --zerocounters - COMMENT "Resetting code coverage counters") - - # custom lcov target to run tests - add_custom_target(lcov-runtests - COMMAND make - DEPENDS lcov-reset - COMMENT "Running all unit tests") - - # get git version description - execute_process(COMMAND git describe --tags - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - OUTPUT_VARIABLE GITDESC - OUTPUT_STRIP_TRAILING_WHITESPACE) - - # command sequence to gather, clean and generate HTML coverage report - add_custom_target(lcov-html - COMMAND ${LCOV} -q --directory . --capture --output-file lcov.info - COMMAND ${LCOV} -q --remove lcov.info '/usr/*' '*/extlib/*' ${LCOV_FLAGS} --output-file lcov-clean.info - COMMAND ${GENHTML} -q -o coverage --title "KaHyPar ${GITDESC}" --prefix ${PROJECT_SOURCE_DIR} ${GENHTML_FLAGS} lcov-clean.info - DEPENDS lcov-runtests - COMMENT "Capturing code coverage counters and create HTML coverage report" - WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - - # top-level target to run tests and generate coverage report - add_custom_target(test-coverage - COMMENT "Generate HTML coverage report" - DEPENDS lcov-html) - + target_compile_options(MtKaHyPar-BuildFlags INTERFACE -fprofile-arcs -ftest-coverage -fprofile-update=atomic) + target_link_options(MtKaHyPar-BuildFlags INTERFACE -lgcov --coverage) endif(KAHYPAR_USE_GCOV) -# Set default build type if not set -if(NOT CMAKE_BUILD_TYPE) - set( CMAKE_BUILD_TYPE Release CACHE STRING - "Choose the type of build, options are: Debug, Release, RelWithDebInfo" - FORCE ) +# lld is way faster than ld. If you have it, use it! +find_program(LLD_BIN lld) +if (LLD_BIN AND KAHYPAR_X86) + message(STATUS "Found and will use LLVM linker " ${LLD_BIN}) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE -fuse-ld=lld) endif() -# Get current commit hash -find_package(Git) -include(GetGitRevisionDescription) -get_git_head_revision(MT_KAHYPAR_VERSION_GIT_REFSPEC MT_KAHYPAR_VERSION_GIT_SHA1) -if(MT_KAHYPAR_VERSION_GIT_REFSPEC) - message(STATUS "Detected git refspec ${MT_KAHYPAR_VERSION_GIT_REFSPEC} sha ${MT_KAHYPAR_VERSION_GIT_SHA1}") - configure_file(${PROJECT_SOURCE_DIR}/mt-kahypar/application/git_revision.txt.in ${PROJECT_BINARY_DIR}/mt-kahypar/application/git_head.txt) -endif(MT_KAHYPAR_VERSION_GIT_REFSPEC) +target_compile_options(MtKaHyPar-BuildFlags INTERFACE $<$:-O3> + $<$:-g3 -UNDEBUG> # keep assertions activated + $<$:-g3 -fno-omit-frame-pointer>) +target_link_options(MtKaHyPar-BuildFlags INTERFACE $<$:-fno-omit-frame-pointer>) -if (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") - set (X86 TRUE) -else () - set (X86 FALSE) -endif () - -if(NOT MSVC) - # Add compile flags - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -W -Wall -Wextra ") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused ") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wuninitialized") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wfatal-errors") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wredundant-decls") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Winit-self") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DPARANOID ") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17") - - if(X86) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcx16") - endif() - - # lld is way faster than ld. If you have it, use it! - find_program(LLD_BIN lld) - if (LLD_BIN AND X86) - message(STATUS "Found and will use LLVM linker " ${LLD_BIN}) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld") - else() - message(STATUS "Default linker") - endif() +if(UNIX AND NOT WIN32) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE $<$:-fsanitize=undefined>) + target_link_options(MtKaHyPar-BuildFlags INTERFACE $<$:-fsanitize=undefined>) +endif() +if (KAHYPAR_X86 AND KAHYPAR_ENABLE_EXTENDED_INSTRUCTIONS) + include(CheckCXXCompilerFlag) include(CheckSSE4_2) - if( BUILTIN_POPCNT ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse4.2") + block() + set(CMAKE_REQUIRED_QUIET TRUE) + check_cxx_compiler_flag(-mcrc32 KAHYPAR_HAS_CRC32) + endblock() + + target_compile_options(MtKaHyPar-BuildFlags INTERFACE -mcx16) + if(KAHYPAR_HAS_CRC32) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE -mcrc32) endif() - - include(CheckCXXCompilerFlag) - check_cxx_compiler_flag(-mcrc32 KAHYPAR_HAS_CRC32) - if(KAHYPAR_HAS_CRC32 AND X86) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mcrc32") + if(BUILTIN_POPCNT) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE -msse4.2) endif() + if(BUILTIN_POPCNT AND CMAKE_SYSTEM_NAME STREQUAL "Linux") + # growt requires SSE instructions + # TODO: it is not clear whether/why Linux is required for growt + target_compile_definitions(MtKaHyPar-BuildFlags INTERFACE KAHYPAR_USE_GROWT) + endif() +endif() +if(KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE $<$:-mtune=native -march=native> + $<$:-mtune=native -march=native>) +endif() - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3 -fno-omit-frame-pointer") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3") - set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g3 ") - - if(UNIX AND NOT WIN32) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g3 -fsanitize=undefined") - endif() +if(KAHYPAR_USE_ADDRESS_SANITIZER AND (NOT KAHYPAR_CI_BUILD)) + target_compile_options(MtKaHyPar-BuildFlags INTERFACE $<$:-fsanitize=address>) + target_link_options(MtKaHyPar-BuildFlags INTERFACE $<$:-fsanitize=address>) +endif() - if(KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS) - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mtune=native -march=native") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -mtune=native -march=native") - endif() - if(KAHYPAR_ADD_ADDRESS_SANITIZER AND (NOT KAHYPAR_CI_BUILD)) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address") - set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address") - endif() +################################################################# +## Include the source code and targets via subdirectories ## +################################################################# - if(ENABLE_PROFILE MATCHES ON) - message(STATUS "Profiling activated") - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DENABLE_PROFILE") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -g3 -DENABLE_PROFILE -fno-omit-frame-pointer") - set(PROFILE_FLAGS "-lprofiler") +if(KAHYPAR_PYTHON) + if (NOT BUILD_SHARED_LIBS) + message(SEND_ERROR "Python interface must be built as shared library. To do so, add -DBUILD_SHARED_LIBS=On to your cmake command.") endif() -elseif(MSVC) - message(FATAL_ERROR "MSVC not supported at the moment") + add_subdirectory(python) +endif() +if (KAHYPAR_ENABLE_TESTING) + add_subdirectory(tests) endif() -add_custom_target(AnalyzeModifiedSources perl "${PROJECT_SOURCE_DIR}/codestyle/analyze-source.pl" "-w") -add_custom_target(AnalyzeAllSources perl "${PROJECT_SOURCE_DIR}/codestyle/analyze-source.pl" "-aw") +add_subdirectory(mt-kahypar/application) +add_subdirectory(tools) +add_subdirectory(lib) +add_subdirectory(mt-kahypar) -message(STATUS "CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") -message(STATUS "CMAKE_CXX_FLAGS_RELEASE: ${CMAKE_CXX_FLAGS_RELEASE}") -message(STATUS "CMAKE_CXX_FLAGS_DEBUG: ${CMAKE_CXX_FLAGS_DEBUG}") -message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") +# export target for C interface +add_library(MtKaHyPar::mtkahypar ALIAS mtkahypar) -include(gmock) -enable_testing() -add_subdirectory(tools) -add_subdirectory(lib) -add_subdirectory(tests) +################################################################# +## Installation ## +################################################################# -if(NOT MT_KAHYPAR_DISABLE_BOOST) - add_subdirectory(mt-kahypar/application) +if(UNIX AND CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + # set default installation prefix if not user-defined + set(CMAKE_INSTALL_PREFIX "/usr/" CACHE STRING "" FORCE) endif() -if(KAHYPAR_PYTHON) - add_subdirectory(python) +if(NOT WIN32 AND BUILD_SHARED_LIBS AND ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + # library installation target + include(SetupInstallation) +endif() + +if(KAHYPAR_INSTALL_CLI AND ${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}) + # CLI installation target + include(GNUInstallDirs) + set_target_properties(MtKaHyPar-CLI PROPERTIES OUTPUT_NAME mtkahypar) + install(TARGETS MtKaHyPar-CLI + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + RENAME mtkahypar + COMPONENT MtKaHyPar_CLI) + add_custom_target(install-mtkahypar-cli + ${CMAKE_COMMAND} + -DBUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_COMPONENT=MtKaHyPar_CLI + -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + DEPENDS MtKaHyPar-CLI) endif() -# This adds the source files. It's important that this happens after the compile targets have been added -add_subdirectory(mt-kahypar) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 000000000..12711d299 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,85 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "minimal", + "displayName": "Minimal config to reduce compile time", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "KAHYPAR_ENABLE_EXTENDED_INSTRUCTIONS": "ON", + "KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS": "ON", + "KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES": "OFF", + "KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES": "OFF", + "KAHYPAR_ENABLE_SOED_METRIC": "OFF", + "KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES": "OFF", + "KAHYPAR_ENABLE_STEINER_TREE_METRIC": "OFF", + "KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES": "OFF" + } + }, + { + "name": "default", + "displayName": "Default config", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "KAHYPAR_ENABLE_EXTENDED_INSTRUCTIONS": "ON", + "KAHYPAR_ENABLE_ARCH_COMPILE_OPTIMIZATIONS": "ON", + "KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES": "ON", + "KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES": "ON", + "KAHYPAR_ENABLE_SOED_METRIC": "ON", + "KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES": "ON", + "KAHYPAR_ENABLE_STEINER_TREE_METRIC": "ON", + "KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES": "OFF" + } + }, + { + "name": "dev", + "displayName": "Developer config", + "inherits": ["default"], + "cacheVariables": { + "KAHYPAR_ENABLE_TESTING": "ON", + "KAHYPAR_USE_ADDRESS_SANITIZER": "ON", + "KAHYPAR_ENABLE_THREAD_PINNING": "ON" + } + }, + { + "name": "python", + "displayName": "Config for Python build", + "inherits": ["default"], + "cacheVariables": { + "KAHYPAR_PYTHON": "ON" + } + }, + { + "name": "all", + "displayName": "All features enabled", + "inherits": ["python"], + "cacheVariables": { + "KAHYPAR_ENABLE_TESTING": "ON", + "KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES": "ON" + } + }, + { + "name": "minimal-dev", + "inherits": ["minimal"], + "cacheVariables": { + "KAHYPAR_ENABLE_TESTING": "ON", + "KAHYPAR_USE_ADDRESS_SANITIZER": "ON", + "KAHYPAR_ENABLE_THREAD_PINNING": "ON" + } + }, + { + "name": "all-dev", + "inherits": ["all", "dev"], + "cacheVariables": { + "KAHYPAR_ENABLE_TESTING": "ON", + "KAHYPAR_USE_ADDRESS_SANITIZER": "ON", + "KAHYPAR_ENABLE_THREAD_PINNING": "ON" + } + } + ] +} diff --git a/README.md b/README.md index ae5b8044b..20921ffd4 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,8 @@ Table of Contents * [Requirements](#requirements) * [Building Mt-KaHyPar](#building-mt-kahypar) * [Running Mt-KaHyPar](#running-mt-kahypar) - * [The C Library Interface](#the-c-library-interface) - * [The Python Library Interface](#the-python-library-interface) + * [Using Mt-KaHyPar as a library](#using-mt-kahypar-as-a-library) * [Supported Objective Functions](#supported-objective-functions) - * [Custom Objective Functions](#custom-objective-functions) * [Improving Compile Times](#improving-compile-times) * [Licensing](#licensing) @@ -23,12 +21,17 @@ About Mt-KaHyPar ----------- Mt-KaHyPar is a shared-memory algorithm for partitioning graphs and hypergraphs. The balanced (hyper)graph partitioning problem asks for a partition of the node set of a (hyper)graph into *k* disjoint blocks of roughly the same size (usually a small imbalance -is allowed by at most 1 + ε times the average block weight), while simultaneously minimizing an objective function defined on the (hyper)edges. Mt-KaHyPar can optimize the cut-net, connectivity, sum-of-external-degrees, and Steiner tree metric (see [Supported Objective Functions](#supported-objective-functions)). +is allowed by at most 1 + ε times the average block weight), while simultaneously minimizing an objective function defined on the (hyper)edges. +Mt-KaHyPar can optimize the cut-net, connectivity, sum-of-external-degrees, and Steiner tree metric (see [Supported Objective Functions](#supported-objective-functions)). alt textalt text -The highest-quality configuration of Mt-KaHyPar computes partitions that are on par with those produced by the best sequential partitioning algorithms, while being almost an order of magnitude faster with only *ten* threads (e.g., when compared to [KaFFPa](https://github.com/KaHIP/KaHIP) or [KaHyPar](https://kahypar.org/)). Besides our high-quality configuration, we provide several other faster configurations that are already able to outperform most of the existing partitioning algorithms with regard to solution quality and running time. -The figure below summarizes the time-quality trade-off of different hypergraph (left, connectivity metric) and graph partitioning algorithms (right, cut-net metric). The plot is based on an experiment with over 800 graphs and hypergraphs and relates the average solution quality and running time of each algorithm to the best achievable results. Points on the lower-left are considered better. Partially transparent markers indicate solvers producing more than 15% infeasible partitions (either imbalanced or timeout). For more details, we refer the reader to our [publications](#licensing). +The highest-quality configuration of Mt-KaHyPar computes partitions that are on par with those produced by the best sequential partitioning algorithms, while being almost an order of magnitude faster with only *ten* threads (e.g., when compared to [KaFFPa](https://github.com/KaHIP/KaHIP) or [KaHyPar](https://kahypar.org/)). +Besides our high-quality configuration, we provide several other faster configurations that are already able to outperform most of the existing partitioning algorithms with regard to solution quality and running time. +The figure below summarizes the time-quality trade-off of different hypergraph (left, connectivity metric) and graph partitioning algorithms (right, cut-net metric). +The plot is based on an experiment with over 800 graphs and hypergraphs and relates the average solution quality and running time of each algorithm to the best achievable results. +Points on the lower-left are considered better. Partially transparent markers indicate solvers producing more than 15% infeasible partitions (either imbalanced or timeout). +For more details, we refer the reader to our [publications](#licensing). ![time_quality_trade_off](https://github.com/kahypar/mt-kahypar/assets/9654047/a5cc1c41-5ca5-496a-ba50-91965e73226b) @@ -42,26 +45,25 @@ Besides its fast and high-quality partitioning algorithm, Mt-KaHyPar provides ma - **Large K Partitioning**: We provide a partitioning configuration for partitioning (hyper)graphs into a large number of blocks (e.g., k > 1024). - **Graph Partitioning**: Mt-KaHyPar includes optimized data structures for graph partitioning, achieving a speedup by a factor of two for plain graphs. - **Objective Functions**: Mt-KaHyPar can optimize the cut-net, connectivity, and sum-of-external-degrees metric (for more details, see [Supported Objective Functions](#supported-objective-functions)) -- **Mapping (Hyper)Graphs Onto Graphs**: In many applications of (hyper)graph partitioning, the blocks of a partition need to be assigned to architectures that can be represented as graphs. For instance, in parallel computations, the blocks may be assigned to processors on a computing cluster interconnected via communication links. It becomes advantageous to position nodes close to each other on the target graph if they are adjacent in the original (hyper)graph. However, conventional objective functions do not consider the topology of the target graph during partitioning. We therefore provide a mode that maps the nodes of a (hyper)graph onto the nodes of a target graph. During this process, the partitioning algorithm optimizes the Steiner tree metric. The objective here is to minimize the total weight of all minimal Steiner trees induced by the (hyper)edges of the hypergraph on the target graph. For more information about this metric, we refer the reader to the [Supported Objective Functions](#supported-objective-functions) section. +- **Mapping (Hyper)Graphs Onto Graphs**: In many applications (e.g., distributed computation), the partition is assigned to a communication network that can be represented as a graph. + However, conventional objective functions do not consider the topology of the target graph. + We therefore provide a mode that maps the nodes of a (hyper)graph onto a target graph via the [Steiner tree metric](#steiner-tree-metric). - **Fixed Vertices**: Fixed vertices are nodes that are preassigned to a particular block and are not allowed to change their block during partitioning. Requirements ----------- -The Multi-Threaded Karlsruhe Graph and Hypergraph Partitioning Framework requires: +Mt-KaHyPar requires: - - A 64-bit Linux, MacOS, or Windows operating system. - - A modern, ![C++17](https://img.shields.io/badge/C++-17-blue.svg?style=flat)-ready compiler such as `g++` version 7 or higher, `clang` version 11.0.3 or higher, or `MinGW` compiler on Windows (tested with version 12.1). - - The [cmake][cmake] build system (>= 3.16). + - A 64-bit Linux, MacOS, or Windows operating system. + - A modern, C++17-ready compiler such as `g++` version 7 or higher, `clang` version 11.0.3 or higher, or `MinGW` compiler on Windows. + - The [cmake][cmake] build system (>= 3.21). - The [Boost - Program Options][Boost.Program_options] library and the boost header files (>= 1.48). If you don't want to install boost by yourself, you can add the `-DKAHYPAR_DOWNLOAD_BOOST=On` flag to the cmake command to download, extract, and build the necessary dependencies automatically. - The [Intel Thread Building Blocks][tbb] library (TBB, minimum required version is OneTBB 2021.5.0). If you don't want to install TBB by yourself, you can add the `-DKAHYPAR_DOWNLOAD_TBB=On` flag (only available on Linux) - to the cmake command to download oneTBB 2021.7.0 and extract the necessary dependencies automatically. - Mt-KaHyPar also compiles with older version of TBB. However, we observed unexpected behaviour of a TBB function - on which we rely on which causes on our side a segmentation fault in really rare cases. If you want to ignore these - warnings, you can add `-DKAHYPAR_ENFORCE_MINIMUM_TBB_VERSION=OFF` to the cmake build command. + to the cmake command to download oneTBB and extract the necessary dependencies automatically. - The [Portable Hardware Locality][hwloc] library (hwloc) ### Linux @@ -88,29 +90,30 @@ The following instructions set up the environment used to build Mt-KaHyPar on Wi 4. The following command will then install all required dependencies: - pacman -S make mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python3 mingw-w64-x86_64-tbb + pacman -S make mingw-w64-x86_64-cmake mingw-w64-x86_64-gcc mingw-w64-x86_64-python3 mingw-w64-x86_64-boost mingw-w64-x86_64-tbb - 5. Rename `libtbb12.dll.a` to `libtbb.dll.a` which is located in `C:\msys64\mingw64\lib` (or `/mingw64/lib` within the - `MSYS2 MinGW x64` terminal) -Please **note** that Mt-KaHyPar was primarily tested and evaluated on Linux machines. While a Windows build has been provided and tested on `MSYS2` using `pacman` to install the required dependencies, we cannot provide any performance guarantees or ensure that the Windows version is free of bugs. At this stage, Windows support is experimental. We are happy to accept contributions to improve Windows support. +Please note that Mt-KaHyPar was primarily tested and evaluated on Linux machines. While a Windows build has been provided and tested on `MSYS2` using `pacman` to install the required dependencies, we cannot provide any performance guarantees or ensure that the Windows version is free of bugs. We are happy to accept contributions to improve Windows support. Building Mt-KaHyPar ----------- -To build Mt-KaHyPar, you can run the `build.sh` script (creates a `build` folder) or use the following commands: +To build Mt-KaHyPar, use the following commands: 1. Clone the repository including submodules: - ```git clone --depth=2 --recursive https://github.com/kahypar/mt-kahypar.git``` + ```git clone https://github.com/kahypar/mt-kahypar.git``` 2. Create a build directory: `mkdir build && cd build` -3. *Only on Windows machines*: `export CMAKE_GENERATOR="MSYS Makefiles"` -3. Run cmake: `cmake .. -DCMAKE_BUILD_TYPE=RELEASE` (on Windows machines add `-DKAHYPAR_DOWNLOAD_BOOST=On`) +3. *Only on Windows machines: `export CMAKE_GENERATOR="MSYS Makefiles"`* +3. Run cmake: `cmake .. --preset=` 4. Run make: `make MtKaHyPar -j` The build produces the executable `MtKaHyPar`, which can be found in `build/mt-kahypar/application/`. +As a user of Mt-KaHyPar, the `default` cmake preset is appropriate (or `python` for installing the Python interface). +If you work on Mt-KaHyPar or want to run benchmarks, use the `dev` preset. + Running Mt-KaHyPar ----------- @@ -124,15 +127,18 @@ Mt-KaHyPar provides several partitioning configurations with different time-qual --preset-type= -- `large_k`: configuration for partitioning (hyper)graphs into a large number of blocks (e.g. >= 1024 blocks, `config/large_k_preset.ini`) -- `deterministic`: configuration for deterministic partitioning (`config/deterministic_preset.ini`, corresponds to Mt-KaHyPar-SDet in our publications) -- `default`: computes good partitions very fast (`config/default_preset.ini`, corresponds to Mt-KaHyPar-D in our publications) -- `quality`: computes high-quality partitions (`config/quality_preset.ini`, corresponds to Mt-KaHyPar-D-F in our publications) -- `highest_quality`: highest-quality configuration (`config/quality_flow_preset.ini`, corresponds to Mt-KaHyPar-Q-F in our publications) +- `large_k`: configuration for partitioning (hyper)graphs into a large number of blocks (e.g. >= 1024 blocks) +- `deterministic`: configuration for deterministic partitioning +- `default`: computes good partitions very fast +- `quality`: computes high-quality partitions (uses flow-based refinement) +- `highest_quality`: highest-quality configuration (uses n-level coarsening and flow-based refinement) The presets can be ranked from lowest to the highest-quality as follows: `large_k`, `deterministic`, `default`, `quality`, and `highest_quality`. -We recommend using the `default` configuration to compute good partitions very fast and the `quality` configuration to compute high-quality solutions. The `highest_quality` configuration computes better partitions than our `quality` configuration by 0.5% on average at the cost of a two times longer running time for medium-sized instances (up to 100 million pins). When you have to partition a (hyper)graph into a large number of blocks (e.g., >= 1024 blocks), you can use our `large_k` configuration. However, we only recommend using this if you experience high running times with one of our other configurations as this can significantly worsen the partitioning quality. +We recommend using the `default` configuration to compute good partitions very fast and the `quality` configuration to compute high-quality solutions. +The `highest_quality` configuration computes better partitions than our `quality` configuration by 0.5% on average at the cost of a two times longer running time for medium-sized instances (up to 100 million pins). +When you have to partition a (hyper)graph into a large number of blocks (e.g., >= 1024 blocks), you can use our `large_k` configuration. +However, we only recommend using this if you experience high running times with one of our other configurations as this can significantly worsen the partitioning quality. ### Objective Functions @@ -140,25 +146,25 @@ Mt-KaHyPar can optimize the cut-net, connectivity, and sum-of-external-degrees m -o -### Mapping (Hyper)Graphs onto Graphs +### Graph Partitioning -To map a **(hyper)graph** onto a **target graph** with Mt-KaHyPar, you can add the following command line parameters to the partitioning call: +To partition a **graph** with Mt-KaHyPar, you can add the following command line parameters to the partitioning call: - -g -o steiner_tree + -h --instance-type=graph --input-file-format= -o cut -The target graph is expected to be in [Metis format](http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf). The nodes of the (hyper)graph are then mapped onto the nodes of the target graph, while optimizing the Steiner tree metric (see [Supported Objective Functions](#supported-objective-functions)). +Mt-KaHyPar then uses optimized data structures for graph partitioning, which speeds up the partitioning time by a factor of two compared to our hypergraph partitioning code. Per default, we expect the input in [hMetis format](mt-kahypar/io/docs/FileFormats.md#hmetis-format-for-input-hypergraphs), but you can read graph files in [Metis format](mt-kahypar/io/docs/FileFormats.md#metis-format-for-input-graphs) via `--input-file-format=metis`. -### Graph Partitioning +### Mapping (Hyper)Graphs onto Graphs -To partition a **graph** with Mt-KaHyPar, you can add the following command line parameters to the partitioning call: +To map a **(hyper)graph** onto a **target graph** with Mt-KaHyPar, you can add the following command line parameters to the partitioning call: - -h --instance-type=graph --input-file-format= -o cut + -g -o steiner_tree -Mt-KaHyPar then uses optimized data structures for graph partitioning, which speedups the partitioning time by a factor of two compared to our hypergraph partitioning code. Per default, we expect the input in [hMetis format](http://glaros.dtc.umn.edu/gkhome/fetch/sw/hmetis/manual.pdf), but you can read graph files in [Metis format](http://glaros.dtc.umn.edu/gkhome/fetch/sw/metis/manual.pdf) via `--input-file-format=metis`. +The target graph is expected to be in [Metis format](mt-kahypar/io/docs/FileFormats.md#metis-format-for-input-graphs). The nodes of the (hyper)graph are then mapped onto the nodes of the target graph, while optimizing the Steiner tree metric (see [Supported Objective Functions](#supported-objective-functions)). ### Fixed Vertices -Fixed vertices are nodes that are preassigned to particular block and are not allowed to change their block during partitioning. Mt-KaHyPar reads fixed vertices from a file in the [hMetis fix file format](http://glaros.dtc.umn.edu/gkhome/fetch/sw/hmetis/manual.pdf), which can be provided via the following command line parameter: +Fixed vertices are nodes that are preassigned to particular block and are not allowed to change their block during partitioning. Mt-KaHyPar reads fixed vertices from a file in the [hMetis fix file format](mt-kahypar/io/docs/FileFormats.md#hmetis-fix-file-format), which can be provided via the following command line parameter: -f @@ -191,19 +197,59 @@ There are several useful options that can provide you with additional insights d If you want to change other configuration parameters manually, please run `--help` for a detailed description of the different program options. -The C Library Interface +Using Mt-KaHyPar as a library ----------- -We provide a simple C-style interface to use Mt-KaHyPar as a library. The library can be built and installed via +We provide a simple C interface to use Mt-KaHyPar as a library, as well as a Python interface. +On Linux or MacOS, the C library can be built and installed via ```sh -make install.mtkahypar # use sudo (Linux & MacOS) or run shell as an administrator (Windows) to install system-wide +make install-mtkahypar # use sudo (Linux & MacOS) or run shell as an administrator (Windows) to install system-wide ``` Note: When installing locally, the build will exit with an error due to missing permissions. However, the library is still built successfully and is available in the build folder. -The library interface can be found in `include/libmtkahypar.h` with a detailed documentation. We also provide several examples in the folder `lib/examples` that show how to use the library. +To remove the library from your system use the provided uninstall target: + +```sh +make uninstall-mtkahypar +``` + +### Integration via Cmake + +If possible, the best way to integrate the C library is directly via cmake using the `MtKaHyPar::mtkahypar` target. + +If the library is installed on the system, it can be used via `find_package`: + +```cmake +find_package(MtKaHyPar) +if(MtKaHyPar_FOUND) + add_executable(example example.cc) + target_link_libraries(example MtKaHyPar::mtkahypar) +endif() +``` + +Alternatively, you can use Mt-KaHyPar directly via `FetchContent`: + +```cmake +FetchContent_Declare( + MtKaHyPar EXCLUDE_FROM_ALL + GIT_REPOSITORY https://github.com/kahypar/mt-kahypar + GIT_TAG v1.5 +) +FetchContent_MakeAvailable(MtKaHyPar) + +add_executable(example example.cc) +target_link_libraries(example MtKaHyPar::mtkahypar) +``` + +When including Mt-KaHyPar directly, it is also possible to control static versus dynamic linking with the `BUILD_SHARED_LIBS` and `KAHYPAR_STATIC_LINK_DEPENDENCIES` cmake options +(note that static linking support is still experimental and not available for the installed library). + +### The C Library Interface + +The library interface can be found in `include/mtkahypar.h` with a detailed documentation. We also provide several examples in the folder `lib/examples` that show how to use the library. Here is a short example of how you can partition a hypergraph using our library interface: @@ -213,12 +259,12 @@ Here is a short example of how you can partition a hypergraph using our library #include #include -#include +#include int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); @@ -270,31 +316,21 @@ int main(int argc, char* argv[]) { } ``` -To compile the program using `g++` run: - -```sh -g++ -std=c++17 -DNDEBUG -O3 your_program.cc -o your_program -lmtkahypar -``` +We recommend [integrating the library via cmake](#integration-via-cmake) into your project, to manage compiling and linking automatically. -To execute the binary, you need to ensure that the installation directory -(probably `/usr/local/lib` (Linux) and `C:\Program Files (x86)\MtKaHyPar\bin` (Windows) for system-wide installation) -is included in the dynamic library path. -The path can be updated on Linux with: +However, it is also possible to directly compile the program using `g++`: ```sh -LD_LIBRARY_PATH="$LD_LIBRARY_PATH;/usr/local/lib" -export LD_LIBRARY_PATH +g++ -std=c++17 -DNDEBUG -O3 your_program.cc -o your_program -lmtkahypar ``` -On Windows, add `C:\Program Files (x86)\KaHyPar\bin` to `PATH` in the environment variables settings. - -To remove the library from your system use the provided uninstall target: +To execute the produced binary, you need to ensure that the installation directory +(probably `/usr/local/lib` on Linux and `C:\Program Files (x86)\MtKaHyPar\bin` on Windows) +is included in the dynamic library path (`LD_LIBRARY_PATH` on Linux, `PATH` on Windows). -```sh -make uninstall-mtkahypar -``` - -**Note** that we internally use different data structures to represent a (hyper)graph based on the corresponding configuration (`mt_kahypar_preset_type_t`). The `mt_kahypar_hypergraph_t` structure stores a pointer to this data structure and also a type description. Therefore, you can not partition a (hyper)graph with all available configurations once it is loaded or constructed. However, you can check the compatibility of a hypergraph with a configuration with the following code: +**Note** that we internally use different data structures to represent a (hyper)graph based on the corresponding configuration (`mt_kahypar_preset_type_t`). +The `mt_kahypar_hypergraph_t` structure stores a pointer to this data structure and also a type description. +Therefore, you can not partition a (hyper)graph with all available configurations once it is loaded or constructed. However, you can check the compatibility of a hypergraph with a configuration with the following code: ```cpp mt_kahypar_context_t context = mt_kahypar_context_new(); @@ -306,8 +342,7 @@ if ( mt_kahypar_check_compatibility(hypergraph, QUALITY) ) { } ``` -The Python Library Interface ------------ +### The Python Library Interface You can install the Python library interface via @@ -318,7 +353,8 @@ make mtkahypar_python This will create a shared library in the `build/python` folder (`mtkahypar.so` on Linux and `mtkahypar.pyd` on Windows). Copy the libary to your Python project directory to import Mt-KaHyPar as a Python module. -A documentation of the Python module can be found in `python/module.cpp`, or by importing the module (`import mtkahypar`) and calling `help(mtkahypar)` in Python. We also provide several examples that show how to use the Python interface in the folder `python/examples`. +A documentation of the Python module can be found in `python/module.cpp`, or by importing the module (`import mtkahypar`) and calling `help(mtkahypar)` in Python. +We also provide several examples that show how to use the Python interface in the folder `python/examples`. Here is a short example of how you can partition a hypergraph using our Python interface: @@ -327,7 +363,7 @@ import multiprocessing import mtkahypar # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() @@ -369,7 +405,10 @@ graph = mtkahypar.Graph( # Partition graph partitioned_graph = graph.partition(context) ``` -**Note** that for partitioning hypergraphs into a large number of blocks (e.g., k > 1024), we recommend using the `LARGE_K` configuration and the `partitionIntoLargeK(...)` function. Using a different configuration for large k partitioning may cause excessive memory usage and high running times, depending on the size of the hypergraph and the memory capacity of your target machine. For partitioning plain graphs, you can load the `LARGE_K` configuration, but you can still use the `partition(...)` function of the graph object. Here is an example that partitions a hypergraph into 1024 blocks: +**Note** that for partitioning hypergraphs into a large number of blocks (e.g., k > 1024), we recommend using the `LARGE_K` configuration and the `partitionIntoLargeK(...)` function. +Using a different configuration for large k partitioning may cause excessive memory usage and high running times, depending on the size of the hypergraph and the memory capacity of your target machine. +For partitioning plain graphs, you can load the `LARGE_K` configuration, but you can still use the `partition(...)` function of the graph object. +Here is an example that partitions a hypergraph into 1024 blocks: ```py # Setup partitioning context @@ -389,44 +428,61 @@ Supported Objective Functions Mt-KaHyPar can optimize several objective functions which we explain in the following in more detail. -**Cut-Net Metric** +### Cut-Net Metric ![cut_net](https://github.com/kahypar/mt-kahypar/assets/9654047/bc7fc7c7-8ac4-4711-8aec-d0526ef2452c) The cut-net metric is defined as total weight of all nets spanning more than one block of the partition Π (also called *cut nets*). -**Connectivity Metric** +### Connectivity Metric ![connectivity](https://github.com/kahypar/mt-kahypar/assets/9654047/1c586ff4-63c3-4260-9ef5-98a76578be46) -The connectivity metric additionally multiplies the weight of each cut net with the number of blocks λ(e) spanned by that net minus one. Thus, the connectivity metric tries to minimize the number of blocks connected by each net. +The connectivity metric additionally multiplies the weight of each cut net with the number of blocks λ(e) spanned by that net minus one. +Thus, the connectivity metric tries to minimize the number of blocks connected by each net. -**Sum-of-external-Degrees Metric** +### Sum-of-external-Degrees Metric ![soed](https://github.com/kahypar/mt-kahypar/assets/9654047/4006fb4c-ac85-452e-a0d9-93d4dc7842ad) -The sum-of-external-degrees metric is similar to the connectivity metric, but does not subtract one from the number of blocks λ(e) spanned by a net. A peculiarity of this objective function is that removing a net from the cut reduces the metric by 2ω(e), while reducing the connectivity by one reduces the metric only by ω(e). Thus, the objective function prefers removing nets from the cut, while as a secondary criterion, it tries to reduce the connectivity of the nets. +The sum-of-external-degrees metric is similar to the connectivity metric, but does not subtract one from the number of blocks λ(e) spanned by a net. +A peculiarity of this objective function is that removing a net from the cut reduces the metric by 2ω(e), while reducing the connectivity by one reduces the metric only by ω(e). +Thus, the objective function prefers removing nets from the cut, while as a secondary criterion, it tries to reduce the connectivity of the nets. -**Steiner Tree Metric** +### Steiner Tree Metric ![steiner_tree](https://github.com/kahypar/mt-kahypar/assets/9654047/926ef7d7-bb6b-4959-af0c-75ebd6f6299f) -The Steiner tree metric is the most versatile metric that we provide at the moment. A Steiner tree is a tree with minimal weight that connects a subset of the nodes on a graph (a more detailed definition can be found [here][SteinerTrees]). For a subset with exactly two nodes, finding a Steiner tree reverts to computing the shortest path between the two nodes. When optimizing the Steiner tree metric, we map the node set of a hypergraph H onto the nodes of a target graph G. The objective is to minimize the total weight of all Steiner trees induced by the nets of H on G. -For a net e, dist(Λ(e)) is the weight of the minimal Steiner tree connecting the blocks Λ(e) spanned by net e on G. The Steiner tree metric can be used to accurately model wire-lengths in VLSI design or communication costs in distributed systems when some processors do not communicate with each other directly or with different speeds. +The Steiner tree metric is the most versatile metric that we provide at the moment. A Steiner tree is a tree with minimal weight that connects a subset of the nodes on a graph (a more detailed definition can be found [here][SteinerTrees]). +For a subset with exactly two nodes, finding a Steiner tree reverts to computing the shortest path between the two nodes. +When optimizing the Steiner tree metric, we map the node set of a hypergraph H onto the nodes of a target graph G. +The objective is to minimize the total weight of all Steiner trees induced by the nets of H on G. +For a net e, dist(Λ(e)) is the weight of the minimal Steiner tree connecting the blocks Λ(e) spanned by net e on G. +The Steiner tree metric can be used to accurately model wire-lengths in VLSI design or communication costs in distributed systems when some processors do not communicate with each other directly or with different speeds. -Note that finding a Steiner tree is an NP-hard problem. We therefore enforce a strict upper bound on the number of nodes of the target graph G which are 64 nodes at the moment. If you want to map a hypergraph onto larger target graphs, you can use recursive multisectioning. For example, if you want to map a hypergraph onto a graph with 4096 nodes, you can first partition the hypergraph into 64 blocks, and then map each block of the partition onto a subgraph of the target graph with 64 nodes. We plan to integrate this technique into Mt-KaHyPar in the future. +Note that finding a Steiner tree is an NP-hard problem. We therefore enforce a strict upper bound on the number of nodes of the target graph G, which is 64 nodes at the moment. +If you want to map a hypergraph onto larger target graphs, you can use recursive partitioning. +For example, if you want to map a hypergraph onto a graph with 4096 nodes, you can first partition the hypergraph into 64 blocks, and then map each block of the partition onto a subgraph of the target graph with 64 nodes. -Custom Objective Functions ------------ +### Custom Objective Functions -We have implemented a common interface for all gain computation techniques that we use in our refinement algorithms. This enables us to extend Mt-KaHyPar with new objective functions without having to modify the internal implementation of the refinement algorithms. A step-by-step guide on how you can implement your own objective function can be found [here][CustomObjectiveFunction]. +Our implementation uses a common interface for all gain computation techniques that we use in our refinement algorithms. +This enables us to extend Mt-KaHyPar with new objective functions without having to modify the internal implementation of the refinement algorithms. +A step-by-step guide on how you can implement your own objective function can be found [here][CustomObjectiveFunction]. Improving Compile Times ----------- -Mt-KaHyPar implements several graph and hypergraph data structures, and supports different objective functions. Each combination of (hyper)graph data structure and objective function is passed to our partitioning algorithms as template parameters. This increases the compile time of Mt-KaHyPar. We therefore provide cmake command line options to disable some of the features of Mt-KaHyPar for faster compilation. The following list summarizes the available parameters: +Mt-KaHyPar implements several graph and hypergraph data structures, and supports different objective functions. +In the hot parts of the algorithm, each combination of (hyper)graph data structure and objective function is compiled separately, which notably increases the compile time. +We therefore provide the cmake preset `minimal` to disable some of the features of Mt-KaHyPar for faster compilation. + +With this, only the `deterministic`, `default`, and `quality` configurations are available in combination with the cut-net or connectivity metric. +Using a disabled feature will throw an error. Note that you can only disable the features in our binary, not in the C and Python interface. + +For more fine-grained control, you can directly use the corresponding cmake flags: ```cmake -DKAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES=On/Off # enables/disables graph partitioning features -DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=On/Off # enables/disables our highest-quality configuration @@ -434,7 +490,6 @@ Mt-KaHyPar implements several graph and hypergraph data structures, and supports -DKAHYPAR_ENABLE_SOED_METRIC=On/Off # enables/disables sum-of-external-degrees metric -DKAHYPAR_ENABLE_STEINER_TREE_METRIC=On/Off # enables/disables Steiner tree metric ``` -If you turn off all features, only the `deterministic`, `default`, and `quality` configurations are available for optimizing the cut-net or connectivity metric. Using a disabled feature will throw an error. Note that you can only disable the features in our binary, not in the C and Python interface. Bug Reports ----------- diff --git a/build.sh b/build.sh deleted file mode 100755 index 3163c681d..000000000 --- a/build.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -function get_num_cores { - if [[ $(uname) == "Linux" ]]; then grep -c ^processor /proc/cpuinfo; fi - if [[ $(uname) == "Darwin" ]]; then sysctl -n hw.ncpu; fi -} - -ROOT=${PWD} -if [ -d .git ]; then - # Mt-KaHyPar is build from a git repository - git submodule update --init --recursive -else - # Mt-KaHyPar is build from a release archive - # which does not include submodules - ./scripts/checkout_submodules.sh -fi - -CMAKE_COMMANDS=$1 -if [ ! -f build/Makefile ]; then - mkdir -p build -fi - -cd build && cmake .. -DCMAKE_BUILD_TYPE=Release $CMAKE_COMMANDS && cd ${ROOT} -cmake --build build --parallel "$(get_num_cores)" --target MtKaHyPar - diff --git a/cmake/MtKaHyParConfig.cmake.in b/cmake/MtKaHyParConfig.cmake.in new file mode 100644 index 000000000..d6f8a7f49 --- /dev/null +++ b/cmake/MtKaHyParConfig.cmake.in @@ -0,0 +1,3 @@ +# Generated by Mt-KaHyPar @MT_KAHYPAR_VERSION@ + +include(${CMAKE_CURRENT_LIST_DIR}/MtKaHyPar.cmake) diff --git a/cmake/MtKaHyParConfigVersion.cmake.in b/cmake/MtKaHyParConfigVersion.cmake.in new file mode 100644 index 000000000..0ec1f2e21 --- /dev/null +++ b/cmake/MtKaHyParConfigVersion.cmake.in @@ -0,0 +1,12 @@ +# Generated by Mt-KaHyPar @MT_KAHYPAR_VERSION@ + +set(PACKAGE_VERSION @MT_KAHYPAR_VERSION@) + +if ("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..de6e8dfba --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,37 @@ +IF(NOT MANIFEST_NAME) + MESSAGE(FATAL_ERROR "MANIFEST_NAME not specified") +ENDIF() + +SET(INSTALL_MANIFEST "@CMAKE_CURRENT_BINARY_DIR@/${MANIFEST_NAME}") +IF(NOT EXISTS ${INSTALL_MANIFEST}) + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"${INSTALL_MANIFEST}\"") +ENDIF() + +FILE(READ "${INSTALL_MANIFEST}" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") + +SET(NUM 0) +FOREACH(file ${files}) + IF(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found") + SET(UNINSTALL_CHECK_${NUM} 1) + ELSE() + MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found") + SET(UNINSTALL_CHECK_${NUM} 0) + ENDIF() + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH() + +SET(NUM 0) +FOREACH(file ${files}) + IF(${UNINSTALL_CHECK_${NUM}}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + FILE(REMOVE "$ENV{DESTDIR}${file}") + IF(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(FATAL_ERROR "Could not remove \"$ENV{DESTDIR}${file}\"") + ENDIF() + ENDIF() + MATH(EXPR NUM "1 + ${NUM}") +ENDFOREACH() + +FILE(REMOVE "${INSTALL_MANIFEST}") diff --git a/cmake/modules/CheckThreadPinning.cmake b/cmake/modules/CheckThreadPinning.cmake new file mode 100644 index 000000000..e7a4681b4 --- /dev/null +++ b/cmake/modules/CheckThreadPinning.cmake @@ -0,0 +1,29 @@ +# Check if the required APIs for thread pinning are available + +set(THREAD_PINNING_WORKS FALSE) +if(UNIX) + # Check if sched_getcpu/sched_setaffinity are available + check_include_files("sched.h" HEADER_AVAILABLE LANGUAGE CXX) + if(${HEADER_AVAILABLE}) + # we need to actually check the available symbols + include(CheckSourceCompiles) + check_source_compiles(CXX + "#include + int main() { + int cpu_id = sched_getcpu(); + int num_cpus = 4; + const size_t size = CPU_ALLOC_SIZE(num_cpus); + cpu_set_t mask; + CPU_ZERO(&mask); + CPU_SET(cpu_id, &mask); + int err = sched_setaffinity(0, size, &mask); + return 0; + }" + EXAMPLE_COMPILES) + if(${EXAMPLE_COMPILES}) + set(THREAD_PINNING_WORKS TRUE) + endif() + endif() +elseif(WIN32) + set(THREAD_PINNING_WORKS TRUE) +endif() diff --git a/cmake/modules/CodeCoverage.cmake b/cmake/modules/CodeCoverage.cmake deleted file mode 100644 index a0b0ef526..000000000 --- a/cmake/modules/CodeCoverage.cmake +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2012 - 2015, Lars Bilke -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# 1. Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# 2. 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. -# -# 3. Neither the name of the copyright holder 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 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. -# -# -# -# 2012-01-31, Lars Bilke -# - Enable Code Coverage -# -# 2013-09-17, Joakim Söderberg -# - Added support for Clang. -# - Some additional usage instructions. -# -# USAGE: - -# 0. (Mac only) If you use Xcode 5.1 make sure to patch geninfo as described here: -# http://stackoverflow.com/a/22404544/80480 -# -# 1. Copy this file into your cmake modules path. -# -# 2. Add the following line to your CMakeLists.txt: -# INCLUDE(CodeCoverage) -# -# 3. 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 SETUP_TARGET_FOR_COVERAGE to create a custom make target -# which runs your test executable and produces a lcov code coverage report: -# Example: -# 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 Debug build: -# cmake -DCMAKE_BUILD_TYPE=Debug .. -# make -# make my_coverage_target -# -# - -# Check prereqs -FIND_PROGRAM( GCOV_PATH gcov ) -FIND_PROGRAM( LCOV_PATH lcov ) -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("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") - IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3) - MESSAGE(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...") - ENDIF() -ELSEIF(NOT CMAKE_COMPILER_IS_GNUCXX) - MESSAGE(FATAL_ERROR "Compiler is not GNU gcc! Aborting...") -ENDIF() # CHECK VALID COMPILER - -SET(CMAKE_CXX_FLAGS_COVERAGE - "-g -O0 --coverage -fprofile-arcs -ftest-coverage" - CACHE STRING "Flags used by the C++ compiler during coverage builds." - FORCE ) -SET(CMAKE_C_FLAGS_COVERAGE - "-g -O0 --coverage -fprofile-arcs -ftest-coverage" - CACHE STRING "Flags used by the C compiler during coverage builds." - FORCE ) -SET(CMAKE_EXE_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used for linking binaries during coverage builds." - FORCE ) -SET(CMAKE_SHARED_LINKER_FLAGS_COVERAGE - "" - CACHE STRING "Flags used by the shared libraries linker during coverage builds." - FORCE ) -MARK_AS_ADVANCED( - CMAKE_CXX_FLAGS_COVERAGE - CMAKE_C_FLAGS_COVERAGE - CMAKE_EXE_LINKER_FLAGS_COVERAGE - CMAKE_SHARED_LINKER_FLAGS_COVERAGE ) - -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" - - -# Param _targetname The name of new the custom make target -# Param _testrunner The name of the target which runs the tests. -# MUST return ZERO always, even on errors. -# If not, no coverage report will be created! -# Param _outputname lcov output is generated as _outputname.info -# HTML report is generated in _outputname/index.html -# Optional fourth parameter is passed as arguments to _testrunner -# Pass them in list form, e.g.: "-j;2" for -j 2 -FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _testrunner _outputname) - - IF(NOT LCOV_PATH) - MESSAGE(FATAL_ERROR "lcov not found! Aborting...") - ENDIF() # NOT LCOV_PATH - - IF(NOT GENHTML_PATH) - MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") - ENDIF() # NOT GENHTML_PATH - - SET(coverage_info "${CMAKE_BINARY_DIR}/${_outputname}.info") - SET(coverage_cleaned "${coverage_info}.cleaned") - - SEPARATE_ARGUMENTS(test_command UNIX_COMMAND "${_testrunner}") - - # Setup target - ADD_CUSTOM_TARGET(${_targetname} - - # Cleanup lcov - ${LCOV_PATH} --directory . --zerocounters - - # Run tests - COMMAND ${test_command} ${ARGV3} - - # Capturing lcov counters and generating report - COMMAND ${LCOV_PATH} --directory . --capture --output-file ${coverage_info} - COMMAND ${LCOV_PATH} --remove ${coverage_info} 'tests/*' '/usr/*' --output-file ${coverage_cleaned} - COMMAND ${GENHTML_PATH} -o ${_outputname} ${coverage_cleaned} - COMMAND ${CMAKE_COMMAND} -E remove ${coverage_info} ${coverage_cleaned} - - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." - ) - - # Show info where to find the report - ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD - COMMAND ; - COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." - ) - -ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE - -# Param _targetname The name of new the custom make target -# Param _testrunner The name of the target which runs the tests -# Param _outputname cobertura output is generated as _outputname.xml -# Optional fourth parameter is passed as arguments to _testrunner -# Pass them in list form, e.g.: "-j;2" for -j 2 -FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) - - IF(NOT PYTHON_EXECUTABLE) - MESSAGE(FATAL_ERROR "Python not found! Aborting...") - ENDIF() # NOT PYTHON_EXECUTABLE - - IF(NOT GCOVR_PATH) - MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") - ENDIF() # NOT GCOVR_PATH - - ADD_CUSTOM_TARGET(${_targetname} - - # Run tests - ${_testrunner} ${ARGV3} - - # Running gcovr - COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT "Running gcovr to produce Cobertura code coverage report." - ) - - # Show info where to find the report - ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD - COMMAND ; - COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." - ) - -ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA diff --git a/cmake/modules/DetectHwloc.cmake b/cmake/modules/DetectHwloc.cmake new file mode 100644 index 000000000..a4efe8a17 --- /dev/null +++ b/cmake/modules/DetectHwloc.cmake @@ -0,0 +1,64 @@ +# Custom script for finding the hwloc library, creates a HWLOC::hwloc target. +# Some complications are necessary in order to also support static linking. +set(HWLOC_TARGET_NAME HWLOC::hwloc) +if(NOT BUILD_SHARED_LIBS AND KAHYPAR_STATIC_LINK_DEPENDENCIES) + set(HWLOC_LINK_STATICALLY TRUE) +endif() + +function(find_hwloc_path) + # search predefined paths + find_path(HWLOC_INCLUDE_DIR NAMES hwloc.h) + find_library(HWLOC_LIBRARY NAMES hwloc) + if(HWLOC_INCLUDE_DIR AND HWLOC_LIBRARY) + message(STATUS "Found hwloc library: inc=${HWLOC_INCLUDE_DIR}, lib=${HWLOC_LIBRARY}") + target_include_directories(hwloc INTERFACE ${HWLOC_INCLUDE_DIR}) + target_link_libraries(hwloc INTERFACE ${HWLOC_LIBRARY}) + set(HWLOC_FOUND TRUE PARENT_SCOPE) + endif() +endfunction() + +if(NOT TARGET ${HWLOC_TARGET_NAME}) + if(HWLOC_LINK_STATICALLY) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + add_library(hwloc INTERFACE IMPORTED) + + find_hwloc_path() + if(NOT HWLOC_FOUND AND HWLOC_LINK_STATICALLY) + message(WARNING "Could not find static version of hwloc library. Proceeding to link dynamically.") + set(HWLOC_LINK_STATICALLY FALSE) + unset(CMAKE_FIND_LIBRARY_SUFFIXES) + find_hwloc_path() + endif() + if(NOT HWLOC_FOUND) + # search for hwloc via pkg_config + find_package(PkgConfig QUIET) + if (PKG_CONFIG_FOUND) + pkg_search_module(HWLOC hwloc IMPORTED_TARGET) + if (TARGET PkgConfig::HWLOC) + target_link_libraries(hwloc INTERFACE PkgConfig::HWLOC) + set(HWLOC_FOUND TRUE) + endif() + endif() + endif() + if(NOT HWLOC_FOUND) + message(FATAL_ERROR "hwloc library not found. Install hwloc on your system.") + endif() + + if(HWLOC_LINK_STATICALLY) + # for static linking we also need udev as transitive dependency of hwloc + find_package(PkgConfig QUIET REQUIRED) + if (PKG_CONFIG_FOUND) + pkg_search_module(UDEV udev IMPORTED_TARGET) + if (TARGET PkgConfig::UDEV) + # -ludev is an annoying workaround since propagating the static dependencies is not properly supported by cmake + target_link_libraries(hwloc INTERFACE PkgConfig::UDEV -ludev) + else() + message(FATAL_ERROR "libudev is required for statically linking hwloc. Install libudev or use -DKAHYPAR_STATIC_LINK_DEPENDENCIES=Off") + endif() + endif() + endif() + + # actual target for outside use + add_library(${HWLOC_TARGET_NAME} ALIAS hwloc) +endif() diff --git a/cmake/modules/FindSparseHash.cmake b/cmake/modules/FindSparseHash.cmake deleted file mode 100644 index 01513a268..000000000 --- a/cmake/modules/FindSparseHash.cmake +++ /dev/null @@ -1,19 +0,0 @@ -# Taken from: https://code.google.com/p/pcsx2/source/browse/trunk/cmake/FindSparseHash.cmake?r=5484 -# Try to find SparseHash -# Once done, this will define -# -# SPARSEHASH_FOUND - system has SparseHash -# SPARSEHASH_INCLUDE_DIR - the SparseHash include directories - -if(SPARSEHASH_INCLUDE_DIR) - set(SPARSEHASH_FIND_QUIETLY TRUE) -endif(SPARSEHASH_INCLUDE_DIR) - -find_path(SPARSEHASH_INCLUDE_DIR google/sparsehash/sparsehashtable.h) - -# handle the QUIETLY and REQUIRED arguments and set SPARSEHASH_FOUND to TRUE if -# all listed variables are TRUE -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(SparseHash DEFAULT_MSG SPARSEHASH_INCLUDE_DIR) - -mark_as_advanced(SPARSEHASH_INCLUDE_DIR) \ No newline at end of file diff --git a/cmake/modules/FindTBB.cmake b/cmake/modules/FindTBB.cmake deleted file mode 100644 index 1e8fbda0c..000000000 --- a/cmake/modules/FindTBB.cmake +++ /dev/null @@ -1,465 +0,0 @@ -# - Find ThreadingBuildingBlocks include dirs and libraries -# Use this module by invoking find_package with the form: -# find_package(TBB -# [REQUIRED] # Fail with error if TBB is not found -# ) # -# Once done, this will define -# -# TBB_FOUND - system has TBB -# TBB_INCLUDE_DIRS - the TBB include directories -# TBB_LIBRARIES - TBB libraries to be lined, doesn't include malloc or -# malloc proxy -# TBB::tbb - imported target for the TBB library -# -# TBB_VERSION_MAJOR - Major Product Version Number -# TBB_VERSION_MINOR - Minor Product Version Number -# TBB_INTERFACE_VERSION - Engineering Focused Version Number -# TBB_COMPATIBLE_INTERFACE_VERSION - The oldest major interface version -# still supported. This uses the engineering -# focused interface version numbers. -# -# TBB_MALLOC_FOUND - system has TBB malloc library -# TBB_MALLOC_INCLUDE_DIRS - the TBB malloc include directories -# TBB_MALLOC_LIBRARIES - The TBB malloc libraries to be lined -# TBB::malloc - imported target for the TBB malloc library -# -# TBB_MALLOC_PROXY_FOUND - system has TBB malloc proxy library -# TBB_MALLOC_PROXY_INCLUDE_DIRS = the TBB malloc proxy include directories -# TBB_MALLOC_PROXY_LIBRARIES - The TBB malloc proxy libraries to be lined -# TBB::malloc_proxy - imported target for the TBB malloc proxy library -# -# -# This module reads hints about search locations from variables: -# ENV TBB_ARCH_PLATFORM - for eg. set it to "mic" for Xeon Phi builds -# ENV TBB_ROOT or just TBB_ROOT - root directory of tbb installation -# ENV TBB_BUILD_PREFIX - specifies the build prefix for user built tbb -# libraries. Should be specified with ENV TBB_ROOT -# and optionally... -# ENV TBB_BUILD_DIR - if build directory is different than ${TBB_ROOT}/build -# -# -# Modified by Robert Maynard from the original OGRE source -# -#------------------------------------------------------------------- -# This file is part of the CMake build system for OGRE -# (Object-oriented Graphics Rendering Engine) -# For the latest info, see http://www.ogre3d.org/ -# -# The contents of this file are placed in the public domain. Feel -# free to make use of it in any way you like. -#------------------------------------------------------------------- -# -# ========================================================================= -# Taken from Copyright.txt in the root of the VTK source tree as per -# instructions to substitute the full license in place of the summary -# reference when distributing outside of VTK -# ========================================================================= -# -# Program: Visualization Toolkit -# Module: Copyright.txt -# -# Copyright (c) 1993-2015 Ken Martin, Will Schroeder, Bill Lorensen -# 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 name of Ken Martin, Will Schroeder, or Bill Lorensen nor the names -# of any 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 AUTHORS 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. -# -# =========================================================================*/ - -#============================================================================= -# FindTBB helper functions and macros -# - -#==================================================== -# Fix the library path in case it is a linker script -#==================================================== -function(tbb_extract_real_library library real_library) - if(NOT UNIX OR NOT EXISTS ${library}) - set(${real_library} "${library}" PARENT_SCOPE) - return() - endif() - - #Read in the first 4 bytes and see if they are the ELF magic number - set(_elf_magic "7f454c46") - file(READ ${library} _hex_data OFFSET 0 LIMIT 4 HEX) - if(_hex_data STREQUAL _elf_magic) - #we have opened a elf binary so this is what - #we should link to - set(${real_library} "${library}" PARENT_SCOPE) - return() - endif() - - file(READ ${library} _data OFFSET 0 LIMIT 1024) - if("${_data}" MATCHES "INPUT \\(([^(]+)\\)") - #extract out the .so name from REGEX MATCH command - set(_proper_so_name "${CMAKE_MATCH_1}") - - #construct path to the real .so which is presumed to be in the same directory - #as the input file - get_filename_component(_so_dir "${library}" DIRECTORY) - set(${real_library} "${_so_dir}/${_proper_so_name}" PARENT_SCOPE) - else() - #unable to determine what this library is so just hope everything works - #and pass it unmodified. - set(${real_library} "${library}" PARENT_SCOPE) - endif() -endfunction() - -#=============================================== -# Do the final processing for the package find. -#=============================================== -macro(findpkg_finish PREFIX TARGET_NAME) - if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) - set(${PREFIX}_FOUND TRUE) - set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) - set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) - else () - if (${PREFIX}_FIND_REQUIRED AND NOT ${PREFIX}_FIND_QUIETLY) - message(FATAL_ERROR "Required library ${PREFIX} not found.") - endif () - endif () - - if (NOT TARGET "TBB::${TARGET_NAME}") - if (${PREFIX}_LIBRARY_RELEASE) - tbb_extract_real_library(${${PREFIX}_LIBRARY_RELEASE} real_release) - endif () - if (${PREFIX}_LIBRARY_DEBUG) - tbb_extract_real_library(${${PREFIX}_LIBRARY_DEBUG} real_debug) - endif () - add_library(TBB::${TARGET_NAME} UNKNOWN IMPORTED) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${${PREFIX}_INCLUDE_DIR}") - if (${PREFIX}_LIBRARY_DEBUG AND ${PREFIX}_LIBRARY_RELEASE) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_release}" - IMPORTED_LOCATION_DEBUG "${real_debug}" - IMPORTED_LOCATION_RELEASE "${real_release}") - elseif (${PREFIX}_LIBRARY_RELEASE) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_release}") - elseif (${PREFIX}_LIBRARY_DEBUG) - set_target_properties(TBB::${TARGET_NAME} PROPERTIES - IMPORTED_LOCATION "${real_debug}") - endif () - endif () - - #mark the following variables as internal variables - mark_as_advanced(${PREFIX}_INCLUDE_DIR - ${PREFIX}_LIBRARY - ${PREFIX}_LIBRARY_DEBUG - ${PREFIX}_LIBRARY_RELEASE) -endmacro() - -#=============================================== -# Generate debug names from given release names -#=============================================== -macro(get_debug_names PREFIX) - foreach(i ${${PREFIX}}) - set(${PREFIX}_DEBUG ${${PREFIX}_DEBUG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) - endforeach() -endmacro() - -#=============================================== -# See if we have env vars to help us find tbb -#=============================================== -macro(getenv_path VAR) - set(ENV_${VAR} $ENV{${VAR}}) - # replace won't work if var is blank - if (ENV_${VAR}) - string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) - endif () -endmacro() - -#=============================================== -# Couple a set of release AND debug libraries -#=============================================== -macro(make_library_set PREFIX) - if (${PREFIX}_RELEASE AND ${PREFIX}_DEBUG) - set(${PREFIX} optimized ${${PREFIX}_RELEASE} debug ${${PREFIX}_DEBUG}) - elseif (${PREFIX}_RELEASE) - set(${PREFIX} ${${PREFIX}_RELEASE}) - elseif (${PREFIX}_DEBUG) - set(${PREFIX} ${${PREFIX}_DEBUG}) - endif () -endmacro() - -#=============================================== -# Ensure that the release & debug libraries found are from the same installation. -#=============================================== -macro(find_tbb_library_verifying_release_debug_locations PREFIX) - find_library(${PREFIX}_RELEASE - NAMES ${${PREFIX}_NAMES} - HINTS ${TBB_LIB_SEARCH_PATH}) - if (${PREFIX}_RELEASE) - # To avoid finding a mismatched set of release & debug libraries from - # different installations if the first found does not have debug libraries - # by forcing the search for debug to only occur within the detected release - # library directory (if found). Although this would break detection if the - # release & debug libraries were shipped in different directories, this is - # not the case in the official TBB releases for any platform. - get_filename_component( - FOUND_RELEASE_LIB_DIR "${${PREFIX}_RELEASE}" DIRECTORY) - find_library(${PREFIX}_DEBUG - NAMES ${${PREFIX}_NAMES_DEBUG} - HINTS ${FOUND_RELEASE_LIB_DIR} - NO_DEFAULT_PATH) - else() - find_library(${PREFIX}_DEBUG - NAMES ${${PREFIX}_NAMES_DEBUG} - HINTS ${TBB_LIB_SEARCH_PATH}) - endif() -endmacro() - -#============================================================================= -# Now to actually find TBB -# - -# Get path, convert backslashes as ${ENV_${var}} -getenv_path(TBB_ROOT) - -# initialize search paths -set(TBB_PREFIX_PATH ${TBB_ROOT} ${ENV_TBB_ROOT}) -set(TBB_INC_SEARCH_PATH "") -set(TBB_LIB_SEARCH_PATH "") - - -# If user built from sources -set(TBB_BUILD_PREFIX $ENV{TBB_BUILD_PREFIX}) -if (TBB_BUILD_PREFIX AND ENV_TBB_ROOT) - getenv_path(TBB_BUILD_DIR) - if (NOT ENV_TBB_BUILD_DIR) - set(ENV_TBB_BUILD_DIR ${ENV_TBB_ROOT}/build) - endif () - - # include directory under ${ENV_TBB_ROOT}/include - list(APPEND TBB_LIB_SEARCH_PATH - ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_release - ${ENV_TBB_BUILD_DIR}/${TBB_BUILD_PREFIX}_debug) -endif () - - -# For Windows, let's assume that the user might be using the precompiled -# TBB packages from the main website. These use a rather awkward directory -# structure (at least for automatically finding the right files) depending -# on platform and compiler, but we'll do our best to accommodate it. -# Not adding the same effort for the precompiled linux builds, though. Those -# have different versions for CC compiler versions and linux kernels which -# will never adequately match the user's setup, so there is no feasible way -# to detect the "best" version to use. The user will have to manually -# select the right files. (Chances are the distributions are shipping their -# custom version of tbb, anyway, so the problem is probably nonexistent.) -if (WIN32 OR MSVC) - set(COMPILER_PREFIX "vc7.1") - if (MSVC_VERSION EQUAL 1400) - set(COMPILER_PREFIX "vc8") - elseif(MSVC_VERSION EQUAL 1500) - set(COMPILER_PREFIX "vc9") - elseif(MSVC_VERSION EQUAL 1600) - set(COMPILER_PREFIX "vc10") - elseif(MSVC_VERSION EQUAL 1700) - set(COMPILER_PREFIX "vc11") - elseif(MSVC_VERSION EQUAL 1800) - set(COMPILER_PREFIX "vc12") - elseif(MSVC_VERSION GREATER_EQUAL 1900) - set(COMPILER_PREFIX "vc14") - endif () - - # for each prefix path, add ia32/64\${COMPILER_PREFIX}\lib to the lib search path - foreach (dir IN LISTS TBB_PREFIX_PATH) - if (CMAKE_CL_64) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia64/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia64/${COMPILER_PREFIX}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${COMPILER_PREFIX}) - else () - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${COMPILER_PREFIX}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${COMPILER_PREFIX}) - endif () - endforeach () -endif () - -# For OS X binary distribution, choose libc++ based libraries for Mavericks (10.9) -# and above and AppleClang -if (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND - NOT CMAKE_SYSTEM_VERSION VERSION_LESS 13.0) - set (USE_LIBCXX OFF) - cmake_policy(GET CMP0025 POLICY_VAR) - - if (POLICY_VAR STREQUAL "NEW") - if (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") - set (USE_LIBCXX ON) - endif () - else () - if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - set (USE_LIBCXX ON) - endif () - endif () - - if (USE_LIBCXX) - foreach (dir IN LISTS TBB_PREFIX_PATH) - list (APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/libc++ ${dir}/libc++/lib) - endforeach () - endif () -endif () - -# check compiler ABI -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.8) - list(APPEND COMPILER_PREFIX "gcc4.8") - endif() - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7) - list(APPEND COMPILER_PREFIX "gcc4.7") - endif() - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.4) - list(APPEND COMPILER_PREFIX "gcc4.4") - endif() - list(APPEND COMPILER_PREFIX "gcc4.1") -elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(COMPILER_PREFIX) - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) # Complete guess - list(APPEND COMPILER_PREFIX "gcc4.8") - endif() - if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.6) - list(APPEND COMPILER_PREFIX "gcc4.7") - endif() - list(APPEND COMPILER_PREFIX "gcc4.4") -else() # Assume compatibility with 4.4 for other compilers - list(APPEND COMPILER_PREFIX "gcc4.4") -endif () - -# if platform architecture is explicitly specified -set(TBB_ARCH_PLATFORM $ENV{TBB_ARCH_PLATFORM}) -if (TBB_ARCH_PLATFORM) - foreach (dir IN LISTS TBB_PREFIX_PATH) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/${TBB_ARCH_PLATFORM}/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/${TBB_ARCH_PLATFORM}) - endforeach () -endif () - -foreach (dir IN LISTS TBB_PREFIX_PATH) - foreach (prefix IN LISTS COMPILER_PREFIX) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/intel64/${prefix}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/intel64/${prefix}/lib) - else () - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib/ia32/${prefix}) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/lib) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/ia32/${prefix}/lib) - endif () - endforeach() -endforeach () - -# add general search paths -foreach (dir IN LISTS TBB_PREFIX_PATH) - list(APPEND TBB_LIB_SEARCH_PATH ${dir}/lib ${dir}/Lib ${dir}/lib/tbb ${dir}/Libs) - list(APPEND TBB_INC_SEARCH_PATH ${dir}/include ${dir}/Include ${dir}/include/tbb ${dir}/include/oneapi/tbb) -endforeach () - -set(TBB_LIBRARY_NAMES tbb) -get_debug_names(TBB_LIBRARY_NAMES) - -find_path(TBB_INCLUDE_DIR - NAMES tbb/tbb.h - HINTS ${TBB_INC_SEARCH_PATH}) -find_tbb_library_verifying_release_debug_locations(TBB_LIBRARY) -make_library_set(TBB_LIBRARY) - -findpkg_finish(TBB tbb) - -#if we haven't found TBB no point on going any further -if (NOT TBB_FOUND) - return() -endif () - -#============================================================================= -# Look for TBB's malloc package -set(TBB_MALLOC_LIBRARY_NAMES tbbmalloc) -get_debug_names(TBB_MALLOC_LIBRARY_NAMES) - -find_path(TBB_MALLOC_INCLUDE_DIR - NAMES tbb/tbb.h - HINTS ${TBB_INC_SEARCH_PATH}) -find_tbb_library_verifying_release_debug_locations(TBB_MALLOC_LIBRARY) -make_library_set(TBB_MALLOC_LIBRARY) - -findpkg_finish(TBB_MALLOC tbbmalloc) - -#============================================================================= -# Look for TBB's malloc proxy package -set(TBB_MALLOC_PROXY_LIBRARY_NAMES tbbmalloc_proxy) -get_debug_names(TBB_MALLOC_PROXY_LIBRARY_NAMES) - -find_path(TBB_MALLOC_PROXY_INCLUDE_DIR - NAMES tbb/tbbmalloc_proxy.h - HINTS ${TBB_INC_SEARCH_PATH}) -find_tbb_library_verifying_release_debug_locations(TBB_MALLOC_PROXY_LIBRARY) -make_library_set(TBB_MALLOC_PROXY_LIBRARY) - -findpkg_finish(TBB_MALLOC_PROXY tbbmalloc_proxy) - - -#============================================================================= -#parse all the version numbers from tbb -if(NOT TBB_VERSION) - set(TBB_VERSION_FILE_PRIOR_TO_TBB_2021_1 - "${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h") - set(TBB_VERSION_FILE_AFTER_TBB_2021_1 - "${TBB_INCLUDE_DIR}/oneapi/tbb/version.h") - - if (EXISTS "${TBB_VERSION_FILE_PRIOR_TO_TBB_2021_1}") - set(TBB_VERSION_FILE "${TBB_VERSION_FILE_PRIOR_TO_TBB_2021_1}") - elseif (EXISTS "${TBB_VERSION_FILE_AFTER_TBB_2021_1}") - set(TBB_VERSION_FILE "${TBB_VERSION_FILE_AFTER_TBB_2021_1}") - else() - message(FATAL_ERROR "Found TBB installation: ${TBB_INCLUDE_DIR} " - "missing version header.") - endif() - - #only read the start of the file - file(STRINGS - "${TBB_VERSION_FILE}" - TBB_VERSION_CONTENTS - REGEX "VERSION") - - string(REGEX REPLACE - ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" - TBB_VERSION_MAJOR "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" - TBB_VERSION_MINOR "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") - - string(REGEX REPLACE - ".*#define TBB_COMPATIBLE_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_COMPATIBLE_INTERFACE_VERSION "${TBB_VERSION_CONTENTS}") - -endif() diff --git a/cmake/modules/GetGitRevisionDescription.cmake b/cmake/modules/GetGitRevisionDescription.cmake deleted file mode 100644 index c8d27f2e8..000000000 --- a/cmake/modules/GetGitRevisionDescription.cmake +++ /dev/null @@ -1,130 +0,0 @@ -# - Returns a version string from Git -# -# These functions force a re-configure on each git commit so that you can -# trust the values of the variables in your build system. -# -# get_git_head_revision( [ ...]) -# -# Returns the refspec and sha hash of the current head revision -# -# git_describe( [ ...]) -# -# Returns the results of git describe on the source tree, and adjusting -# the output so that it tests false if an error occurs. -# -# git_get_exact_tag( [ ...]) -# -# Returns the results of git describe --exact-match on the source tree, -# and adjusting the output so that it tests false if there was no exact -# matching tag. -# -# Requires CMake 2.6 or newer (uses the 'function' command) -# -# Original Author: -# 2009-2010 Ryan Pavlik -# http://academic.cleardefinition.com -# Iowa State University HCI Graduate Program/VRAC -# -# Copyright Iowa State University 2009-2010. -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -if(__get_git_revision_description) - return() -endif() -set(__get_git_revision_description YES) - -# We must run the following at "include" time, not at function call time, -# to find the path to this module rather than the path to a calling list file -get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH) - -function(get_git_head_revision _refspecvar _hashvar) - set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - set(GIT_DIR "${GIT_PARENT_DIR}/.git") - while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories - set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}") - get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH) - if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT) - # We have reached the root directory, we are not in git - set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE) - set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE) - return() - endif() - set(GIT_DIR "${GIT_PARENT_DIR}/.git") - endwhile() - # check if this is a submodule - if(NOT IS_DIRECTORY ${GIT_DIR}) - file(READ ${GIT_DIR} submodule) - string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule}) - get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH) - get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE) - endif() - set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data") - if(NOT EXISTS "${GIT_DATA}") - file(MAKE_DIRECTORY "${GIT_DATA}") - endif() - - if(NOT EXISTS "${GIT_DIR}/HEAD") - return() - endif() - set(HEAD_FILE "${GIT_DATA}/HEAD") - configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY) - - configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in" - "${GIT_DATA}/grabRef.cmake" - @ONLY) - include("${GIT_DATA}/grabRef.cmake") - - set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE) - set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE) -endfunction() - -function(git_describe _var) - if(NOT GIT_FOUND) - find_package(Git QUIET) - endif() - get_git_head_revision(refspec hash) - if(NOT GIT_FOUND) - set(${_var} "GIT-NOTFOUND" PARENT_SCOPE) - return() - endif() - if(NOT hash) - set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE) - return() - endif() - - # TODO sanitize - #if((${ARGN}" MATCHES "&&") OR - # (ARGN MATCHES "||") OR - # (ARGN MATCHES "\\;")) - # message("Please report the following error to the project!") - # message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}") - #endif() - - #message(STATUS "Arguments to execute_process: ${ARGN}") - - execute_process(COMMAND - "${GIT_EXECUTABLE}" - describe - ${hash} - ${ARGN} - WORKING_DIRECTORY - "${CMAKE_SOURCE_DIR}" - RESULT_VARIABLE - res - OUTPUT_VARIABLE - out - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE) - if(NOT res EQUAL 0) - set(out "${out}-${res}-NOTFOUND") - endif() - - set(${_var} "${out}" PARENT_SCOPE) -endfunction() - -function(git_get_exact_tag _var) - git_describe(out --exact-match ${ARGN}) - set(${_var} "${out}" PARENT_SCOPE) -endfunction() diff --git a/cmake/modules/GetGitRevisionDescription.cmake.in b/cmake/modules/GetGitRevisionDescription.cmake.in deleted file mode 100644 index b7ec34769..000000000 --- a/cmake/modules/GetGitRevisionDescription.cmake.in +++ /dev/null @@ -1,37 +0,0 @@ -# Internal file for GetGitRevisionDescription.cmake -# -# Requires CMake 2.6 or newer (uses the 'function' command) -# -# Original Author: -# 2009-2010 Ryan Pavlik -# http://academic.cleardefinition.com -# Iowa State University HCI Graduate Program/VRAC -# -# Copyright Iowa State University 2009-2010. -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -set(HEAD_HASH) - -file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024) - -string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS) -if(HEAD_CONTENTS MATCHES "ref") - # named branch - string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}") - if(EXISTS "@GIT_DIR@/${HEAD_REF}") - configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}") - configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY) - set(HEAD_HASH "${HEAD_REF}") - endif() -else() - # detached HEAD - configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY) -endif() - -if(NOT HEAD_HASH) - file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024) - string(STRIP "${HEAD_HASH}" HEAD_HASH) -endif() diff --git a/cmake/modules/GetGitRevisionDescription.cmake_files/indicator.html b/cmake/modules/GetGitRevisionDescription.cmake_files/indicator.html deleted file mode 100644 index 37dad40a7..000000000 --- a/cmake/modules/GetGitRevisionDescription.cmake_files/indicator.html +++ /dev/null @@ -1,91 +0,0 @@ - - - - - Readability Activity Indicator - - - - - - - - - - \ No newline at end of file diff --git a/cmake/modules/README.rst b/cmake/modules/README.rst deleted file mode 100644 index 3b16c37c1..000000000 --- a/cmake/modules/README.rst +++ /dev/null @@ -1,360 +0,0 @@ -.. contents:: - -Introduction ------------- -Many developers use CMake to manage their development projects, so the Threading Building Blocks (TBB) -team created the set of CMake modules to simplify integration of the TBB library into a CMake project. -The modules are available starting from TBB 2017 U7 in `/cmake `_. - -About TBB -^^^^^^^^^^^^^^^ -TBB is a library that supports scalable parallel programming using standard ISO C++ code. It does not require special languages or compilers. It is designed to promote scalable data parallel programming. Additionally, it fully supports nested parallelism, so you can build larger parallel components from smaller parallel components. To use the library, you specify tasks, not threads, and let the library map tasks onto threads in an efficient manner. - -Many of the library interfaces employ generic programming, in which interfaces are defined by requirements on types and not specific types. The C++ Standard Template Library (STL) is an example of generic programming. Generic programming enables TBB to be flexible yet efficient. The generic interfaces enable you to customize components to your specific needs. - -The net result is that TBB enables you to specify parallelism far more conveniently than using raw threads, and at the same time can improve performance. - -References -^^^^^^^^^^ -* `Official TBB open source site `_ -* `Official GitHub repository `_ - -Engineering team contacts -^^^^^^^^^^^^^^^^^^^^^^^^^ -The TBB team is very interested in convenient integration of the TBB library into customer projects. These CMake modules were created to provide such a possibility for CMake projects using a simple but powerful interface. We hope you will try these modules and we are looking forward to receiving your feedback! - -E-mail us: `inteltbbdevelopers@intel.com `_. - -Visit our `forum `_. - -Release Notes -------------- -* Minimum supported CMake version: ``3.0.0``. -* TBB versioning via `find_package `_ has the following format: ``find_package(TBB .. ...)``. TBB interface version can also be obtained in the customer project via the ``TBB_INTERFACE_VERSION`` variable. - -Use cases of TBB integration into CMake-aware projects ------------------------------------------------------------- -There are two types of TBB packages: - * Binary packages with pre-built binaries for Windows* OS, Linux* OS and macOS*. They are available on the releases page of the Github repository: https://github.com/01org/tbb/releases. The main purpose of the binary package integration is the ability to build TBB header files and binaries into your CMake-aware project. - * A source package is also available to download from the release page via the "Source code" link. In addition, it can be cloned from the repository by ``git clone https://github.com/01org/tbb.git``. The main purpose of the source package integration is to allow you to do a custom build of the TBB library from the source files and then build that into your CMake-aware project. - -There are four types of CMake modules that can be used to integrate TBB: `TBBConfig`, `TBBGet`, `TBBMakeConfig` and `TBBBuild`. See `Technical documentation for CMake modules`_ section for additional details. - -Binary package integration -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The following use case is valid for packages starting from TBB 2017 U7: - -* Download package manually and make integration. - - Pre-condition: Location of TBBConfig.cmake is available via ``TBB_DIR`` or ``CMAKE_PREFIX_PATH`` contains path to TBB root. - - CMake code for integration: - .. code:: cmake - - find_package(TBB ) - -The following use case is valid for all TBB 2017 packages. - -* Download package using TBBGet_ and make integration. - - Pre-condition: TBB CMake modules are available via . - - CMake code for integration: - .. code:: cmake - - include(/TBBGet.cmake) - tbb_get(TBB_ROOT tbb_root CONFIG_DIR TBB_DIR) - find_package(TBB ) - -Source package integration -^^^^^^^^^^^^^^^^^^^^^^^^^^ -* Build TBB from existing source files using TBBBuild_ and make integration. - - Pre-condition: TBB source code is available via and TBB CMake modules are available via . - - CMake code for integration: - .. code:: cmake - - include(/TBBBuild.cmake) - tbb_build(TBB_ROOT CONFIG_DIR TBB_DIR) - find_package(TBB ) - -* Download TBB source files using TBBGet_, build it using TBBBuild_ and make integration. - - Pre-condition: TBB CMake modules are available via . - - CMake code for integration: - .. code:: cmake - - include(/TBBGet.cmake) - include(/TBBBuild.cmake) - tbb_get(TBB_ROOT tbb_root SOURCE_CODE) - tbb_build(TBB_ROOT ${tbb_root} CONFIG_DIR TBB_DIR) - find_package(TBB ) - -Tutorials: TBB integration using CMake --------------------------------------------- -Binary TBB integration to the sub_string_finder sample (Windows* OS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In this example, we will integrate binary TBB package into the sub_string_finder sample on Windows* OS (Microsoft* Visual Studio). -This example is also applicable for other platforms with slight changes. -Place holders and should be replaced with the actual values for the TBB package being used. The example is written for `CMake 3.7.1`. - -Precondition: - * `Microsoft* Visual Studio 11` or higher. - * `CMake 3.0.0` or higher. - -#. Download the latest binary package for Windows from `this page `_ and unpack it to the directory ``C:\demo_tbb_cmake``. -#. In the directory ``C:\demo_tbb_cmake\tbb_oss\examples\GettingStarted\sub_string_finder`` create ``CMakeLists.txt`` file with the following content: - .. code:: cmake - - cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) - - project(sub_string_finder CXX) - add_executable(sub_string_finder sub_string_finder.cpp) - - # find_package will search for available TBBConfig using variables CMAKE_PREFIX_PATH and TBB_DIR. - find_package(TBB REQUIRED tbb) - - # Link TBB imported targets to the executable; - # "TBB::tbb" can be used instead of "${TBB_IMPORTED_TARGETS}". - target_link_libraries(sub_string_finder ${TBB_IMPORTED_TARGETS}) -#. Run CMake GUI and: - * Fill the following fields (you can use the buttons ``Browse Source...`` and ``Browse Build...`` accordingly) - - * Where is the source code: ``C:/demo_tbb_cmake/tbb_oss/examples/GettingStarted/sub_string_finder`` - * Where to build the binaries: ``C:/demo_tbb_cmake/tbb_oss/examples/GettingStarted/sub_string_finder/build`` - - * Add new cache entry using button ``Add Entry`` to let CMake know where to search for TBBConfig: - - * Name: ``CMAKE_PREFIX_PATH`` - * Type: ``PATH`` - * Value: ``C:/demo_tbb_cmake/tbb_oss`` - - * Push the button ``Generate`` and choose a proper generator for your Microsoft* Visual Studio version. -#. Now you can open the generated solution ``C:/demo_tbb_cmake/tbb_oss/examples/GettingStarted/sub_string_finder/build/sub_string_finder.sln`` in your Microsoft* Visual Studio and build it. - -Source code integration of TBB to the sub_string_finder sample (Linux* OS) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In this example, we will build TBB from source code with enabled Community Preview Features and link the sub_string_finder sample with the built library. -This example is also applicable for other platforms with slight changes. - -Precondition: - * `CMake 3.0.0` or higher. - * `Git` (to clone the TBB repository from GitHub) - -#. Create the directory ``~/demo_tbb_cmake``, go to the created directory and clone the TBB repository there: - ``mkdir ~/demo_tbb_cmake ; cd ~/demo_tbb_cmake ; git clone https://github.com/01org/tbb.git`` -#. In the directory ``~/demo_tbb_cmake/tbb/examples/GettingStarted/sub_string_finder`` create ``CMakeLists.txt`` file with following content: - .. code:: cmake - - cmake_minimum_required(VERSION 3.0.0 FATAL_ERROR) - - project(sub_string_finder CXX) - add_executable(sub_string_finder sub_string_finder.cpp) - - include(${TBB_ROOT}/cmake/TBBBuild.cmake) - - # Build TBB with enabled Community Preview Features (CPF). - tbb_build(TBB_ROOT ${TBB_ROOT} CONFIG_DIR TBB_DIR MAKE_ARGS tbb_cpf=1) - - find_package(TBB REQUIRED tbb_preview) - - # Link TBB imported targets to the executable; - # "TBB::tbb_preview" can be used instead of "${TBB_IMPORTED_TARGETS}". - target_link_libraries(sub_string_finder ${TBB_IMPORTED_TARGETS}) -#. Create a build directory for the sub_string_finder sample to perform build out of source, go to the created directory - ``mkdir ~/demo_tbb_cmake/tbb/examples/GettingStarted/sub_string_finder/build ; cd ~/demo_tbb_cmake/tbb/examples/GettingStarted/sub_string_finder/build`` -#. Run CMake to prepare Makefile for the sub_string_finder sample and provide TBB location (root) where to perform build: - ``cmake -DTBB_ROOT=${HOME}/demo_tbb_cmake/tbb ..`` -#. Make an executable and run it: - ``make ; ./sub_string_finder`` - -Technical documentation for CMake modules ------------------------------------------ -TBBConfig -^^^^^^^^^ - -Configuration module for TBB library. - -How to use this module in your CMake project: - #. Add location of TBB (root) to `CMAKE_PREFIX_PATH `_ - or specify location of TBBConfig.cmake in ``TBB_DIR``. - #. Use `find_package `_ to configure TBB. - #. Use provided variables and/or imported targets (described below) to work with TBB. - -TBB components can be passed to `find_package `_ -after keyword ``COMPONENTS`` or ``REQUIRED``. -Use basic names of components (``tbb``, ``tbbmalloc``, ``tbb_preview``, etc.). - -If components are not specified then default are used: ``tbb``, ``tbbmalloc`` and ``tbbmalloc_proxy``. - -If ``tbbmalloc_proxy`` is requested, ``tbbmalloc`` component will also be added and set as dependency for ``tbbmalloc_proxy``. - -TBBConfig creates `imported targets `_ as -shared libraries using the following format: ``TBB::`` (for example, ``TBB::tbb``, ``TBB::tbbmalloc``). - -Variables set during TBB configuration: - -========================= ================================================ - Variable Description -========================= ================================================ -``TBB_FOUND`` TBB library is found -``TBB__FOUND`` specific TBB component is found -``TBB_IMPORTED_TARGETS`` all created TBB imported targets -``TBB_VERSION`` TBB version (format: ``.``) -``TBB_INTERFACE_VERSION`` TBB interface version -========================= ================================================ - -TBBInstallConfig -^^^^^^^^^^^^^^^^ - -Module for generation and installation of TBB CMake configuration files (TBBConfig.cmake and TBBConfigVersion.cmake files) on Linux, macOS and Windows. - -Provides the following functions: - - .. code:: cmake - - tbb_install_config(INSTALL_DIR SYSTEM_NAME Linux|Darwin|Windows - [TBB_VERSION ..|TBB_VERSION_FILE ] - [LIB_REL_PATH INC_REL_PATH ] - [LIB_PATH INC_PATH ])`` - -**Note: the module overwrites existing TBBConfig.cmake and TBBConfigVersion.cmake files in .** - -``tbb_config_installer.cmake`` allows to run ``TBBInstallConfig.cmake`` from command line. -It accepts the same parameters as ``tbb_install_config`` function, run ``cmake -P tbb_config_installer.cmake`` to get help. - -Use cases -""""""""" -**Prepare TBB CMake configuration files for custom TBB package.** - -The use case is applicable for package maintainers who create own TBB packages and want to create TBBConfig.cmake and TBBConfigVersion.cmake for these packages. - -=========================================== =========================================================== - Parameter Description -=========================================== =========================================================== -``INSTALL_DIR `` Directory to install CMake configuration files -``SYSTEM_NAME Linux|Darwin|Windows`` OS name to generate config files for -``TBB_VERSION_FILE `` Path to ``tbb_stddef.h`` to parse version from and - write it to TBBConfigVersion.cmake -``TBB_VERSION ..`` Directly specified TBB version; - alternative to ``TBB_VERSION_FILE`` parameter -``LIB_REL_PATH `` Relative path to TBB binaries (.lib files on Windows), default: ``../../../lib`` -``BIN_REL_PATH `` Relative path to TBB DLLs, default: ``../../../bin`` (applicable for Windows only) -``INC_REL_PATH `` Relative path to TBB headers, default: ``../../../include`` -=========================================== =========================================================== - -*Example* - - Assume your package is installed to the following structure: - - * Binaries go to ``/lib`` - * Headers go to ``/include`` - * CMake configuration files go to ``/lib/cmake/`` - - The package is packed from ``/my/package/content`` directory. - - ``cmake -DINSTALL_DIR=/my/package/content/lib/cmake/TBB -DSYSTEM_NAME=Linux -DTBB_VERSION_FILE=/my/package/content/include/tbb/tbb_stddef.h -P tbb_config_installer.cmake`` (default relative paths will be used) - -**Install TBB CMake configuration files for installed TBB.** - -The use case is applicable for users who have installed TBB, but do not have (or have incorrect) CMake configuration files for this TBB. - -==================================== ============================================== - Parameter Description -==================================== ============================================== -``INSTALL_DIR `` Directory to install CMake configuration files -``SYSTEM_NAME Linux|Darwin|Windows`` OS name to generate config files for -``LIB_PATH `` Path to installed TBB binaries (.lib files on Windows) -``BIN_PATH `` Path to installed TBB DLLs (applicable for Windows only) -``INC_PATH `` Path to installed TBB headers -==================================== ============================================== - -``LIB_PATH`` and ``INC_PATH`` will be converted to relative paths based on ``INSTALL_DIR``. -By default TBB version will be parsed from ``/tbb/tbb_stddef.h``, -but it can be overridden by optional parameters ``TBB_VERSION_FILE`` or ``TBB_VERSION``. - -*Example* - - TBB is installed to ``/usr`` directory. - In order to create TBBConfig.cmake and TBBConfigVersion.cmake in ``/usr/lib/cmake/TBB`` run - - ``cmake -DINSTALL_DIR=/usr/lib/cmake/TBB -DSYSTEM_NAME=Linux -DLIB_PATH=/usr/lib -DINC_PATH=/usr/include -P tbb_config_installer.cmake``. - -TBBGet -^^^^^^ - -Module for getting TBB library from `GitHub `_. - -Provides the following functions: - ``tbb_get(TBB_ROOT [RELEASE_TAG |LATEST] [SAVE_TO ] [SYSTEM_NAME Linux|Windows|Darwin] [CONFIG_DIR | SOURCE_CODE])`` - downloads TBB from GitHub and creates TBBConfig for the downloaded binary package if there is no TBBConfig. - - ==================================== ==================================== - Parameter Description - ==================================== ==================================== - ``TBB_ROOT `` a variable to save TBB root in, ``-NOTFOUND`` will be provided in case ``tbb_get`` is unsuccessful - ``RELEASE_TAG |LATEST`` TBB release tag to be downloaded (for example, ``2017_U6``), ``LATEST`` is used by default - ``SAVE_TO `` path to location at which to unpack downloaded TBB, ``${CMAKE_CURRENT_BINARY_DIR}/tbb_downloaded`` is used by default - ``SYSTEM_NAME Linux|Windows|Darwin`` operating system name to download a binary package for, - value of `CMAKE_SYSTEM_NAME `_ is used by default - ``CONFIG_DIR `` a variable to save location of TBBConfig.cmake and TBBConfigVersion.cmake. Ignored if ``SOURCE_CODE`` specified - ``SOURCE_CODE`` flag to get TBB source code (instead of binary package) - ==================================== ==================================== - -TBBMakeConfig -^^^^^^^^^^^^^ - -Module for making TBBConfig in `official TBB binary packages published on GitHub `_. - -This module is to be used for packages that do not have TBBConfig. - -Provides the following functions: - ``tbb_make_config(TBB_ROOT CONFIG_DIR [SYSTEM_NAME Linux|Windows|Darwin])`` - creates CMake configuration files (TBBConfig.cmake and TBBConfigVersion.cmake) for TBB binary package. - - ==================================== ==================================== - Parameter Description - ==================================== ==================================== - ``TBB_ROOT `` path to TBB root - ``CONFIG_DIR `` a variable to store location of the created configuration files - ``SYSTEM_NAME Linux|Windows|Darwin`` operating system name of the binary TBB package, - value of `CMAKE_SYSTEM_NAME `_ is used by default - ==================================== ==================================== - -TBBBuild -^^^^^^^^ - -Module for building TBB library from the source code. - -Provides the following functions: - ``tbb_build(TBB_ROOT CONFIG_DIR [MAKE_ARGS ])`` - builds TBB from source code using the ``Makefile``, creates and provides the location of the CMake configuration files (TBBConfig.cmake and TBBConfigVersion.cmake) . - - ===================================== ==================================== - Parameter Description - ===================================== ==================================== - ``TBB_ROOT `` path to TBB root - ``CONFIG_DIR `` a variable to store location of the created configuration files, - ``-NOTFOUND`` will be provided in case ``tbb_build`` is unsuccessful - ``MAKE_ARGS `` custom arguments to be passed to ``make`` tool. - - The following arguments are always passed with automatically detected values to - ``make`` tool if they are not redefined in ````: - - - ``compiler=`` - - ``tbb_build_dir=`` - - ``tbb_build_prefix=`` - - ``-j`` - ===================================== ==================================== - - ------------- - -Intel and the Intel logo are trademarks of Intel Corporation or its subsidiaries in the U.S. and/or other countries. - -``*`` Other names and brands may be claimed as the property of others. diff --git a/cmake/modules/SetupInstallation.cmake b/cmake/modules/SetupInstallation.cmake new file mode 100644 index 000000000..2b1af0b80 --- /dev/null +++ b/cmake/modules/SetupInstallation.cmake @@ -0,0 +1,48 @@ +# Script that creates the installation targets for a shared library + +include(GNUInstallDirs) + +set_target_properties(mtkahypar PROPERTIES + VERSION ${MT_KAHYPAR_VERSION} SOVERSION ${MT_KAHYPAR_SO_VERSION}) +set_target_properties(mtkahypar PROPERTIES + PUBLIC_HEADER "${MTKAHYPAR_INCLUDE_DIR}/mtkahypar.h;${MTKAHYPAR_INCLUDE_DIR}/mtkahypartypes.h") + +configure_file(cmake/mtkahypar.pc.in mtkahypar.pc @ONLY) +configure_file(cmake/MtKaHyParConfig.cmake.in MtKaHyParConfig.cmake @ONLY) +configure_file(cmake/MtKaHyParConfigVersion.cmake.in MtKaHyParConfigVersion.cmake @ONLY) + +install(FILES ${CMAKE_BINARY_DIR}/mtkahypar.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + COMPONENT MtKaHyPar_Lib) + +install(FILES ${CMAKE_BINARY_DIR}/MtKaHyParConfig.cmake + ${CMAKE_BINARY_DIR}/MtKaHyParConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MtKaHyPar + COMPONENT MtKaHyPar_Lib) + +install(TARGETS mtkahypar + EXPORT MtKaHyPar + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT MtKaHyPar_Lib + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT MtKaHyPar_Lib) + +install(EXPORT MtKaHyPar + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MtKaHyPar + FILE MtKaHyPar.cmake + NAMESPACE MtKaHyPar:: + COMPONENT MtKaHyPar_Lib) + +# custom targets for installing/uninstalling the library +add_custom_target(install-mtkahypar + ${CMAKE_COMMAND} + -DBUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_INSTALL_COMPONENT=MtKaHyPar_Lib + -P ${CMAKE_BINARY_DIR}/cmake_install.cmake + DEPENDS mtkahypar) + +configure_file(cmake/cmake_uninstall.cmake.in cmake_uninstall.cmake IMMEDIATE @ONLY) +add_custom_target(uninstall-mtkahypar + "${CMAKE_COMMAND}" + -DMANIFEST_NAME=install_manifest_MtKaHyPar_Lib.txt + -P ${CMAKE_BINARY_DIR}/cmake_uninstall.cmake) diff --git a/cmake/modules/TBBBuild.cmake b/cmake/modules/TBBBuild.cmake deleted file mode 100644 index a2222e357..000000000 --- a/cmake/modules/TBBBuild.cmake +++ /dev/null @@ -1,197 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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. - -# -# Usage: -# include(TBBBuild.cmake) -# tbb_build(TBB_ROOT CONFIG_DIR MAKE_ARGS [... ]) -# find_package(TBB ) -# - -include(CMakeParseArguments) - -# Save the location of Intel TBB CMake modules here, as it will not be possible to do inside functions, -# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html -set(_tbb_cmake_module_path ${CMAKE_CURRENT_LIST_DIR}) - -## -# Builds Intel TBB. -# -# Parameters: -# TBB_ROOT - path to Intel TBB root directory (with sources); -# MAKE_ARGS - user-defined arguments to be passed to make-tool; -# CONFIG_DIR - store location of the created TBBConfig if the build was ok, store -NOTFOUND otherwise. -# -function(tbb_build) - # NOTE: internal function are used to hide them from user. - - ## - # Provides arguments for make-command to build Intel TBB. - # - # Following arguments are provided automatically if they are not defined by user: - # compiler= - # tbb_build_dir= - # tbb_build_prefix= - # -j - # - # Parameters: - # USER_DEFINED_ARGS - list of user-defined arguments; - # RESULT - resulting list of 'make' arguments. - # - function(tbb_get_make_args) - set(oneValueArgs RESULT) - set(multiValueArgs USER_DEFINED_ARGS) - cmake_parse_arguments(tbb_GMA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - set(result ${tbb_GMA_USER_DEFINED_ARGS}) - - if (NOT tbb_GMA_USER_DEFINED_ARGS MATCHES "compiler=") - # TODO: add other supported compilers. - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(compiler gcc) - elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") - set(compiler icc) - if (CMAKE_SYSTEM_NAME MATCHES "Windows") - set(compiler icl) - endif() - elseif (MSVC) - set(compiler cl) - elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(compiler clang) - endif() - - set(result "compiler=${compiler}" ${result}) - endif() - - if (NOT tbb_GMA_USER_DEFINED_ARGS MATCHES "stdver=" AND DEFINED CMAKE_CXX_STANDARD) - set(result "stdver=c++${CMAKE_CXX_STANDARD}" ${result}) - endif() - - if (NOT tbb_GMA_USER_DEFINED_ARGS MATCHES "tbb_build_dir=") - set(result "tbb_build_dir=${CMAKE_CURRENT_BINARY_DIR}/tbb_cmake_build" ${result}) - endif() - - if (NOT tbb_GMA_USER_DEFINED_ARGS MATCHES "tbb_build_prefix=") - set(result "tbb_build_prefix=tbb_cmake_build_subdir" ${result}) - endif() - - if (NOT tbb_GMA_USER_DEFINED_ARGS MATCHES "(;|^) *\\-j[0-9]* *(;|$)") - include(ProcessorCount) - ProcessorCount(num_of_cores) - if (NOT num_of_cores EQUAL 0) - set(result "-j${num_of_cores}" ${result}) - endif() - endif() - - if (CMAKE_SYSTEM_NAME MATCHES "Android") - set(result target=android ${result}) - endif() - - set(${tbb_GMA_RESULT} ${result} PARENT_SCOPE) - endfunction() - - ## - # Provides release and debug directories basing on 'make' arguments. - # - # Following 'make' arguments are parsed: tbb_build_dir, tbb_build_prefix - # - # Parameters: - # MAKE_ARGS - 'make' arguments (tbb_build_dir and tbb_build_prefix are required) - # RELEASE_DIR - store normalized (CMake) path to release directory - # DEBUG_DIR - store normalized (CMake) path to debug directory - # - function(tbb_get_build_paths_from_make_args) - set(oneValueArgs RELEASE_DIR DEBUG_DIR) - set(multiValueArgs MAKE_ARGS) - cmake_parse_arguments(tbb_GBPFMA "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - foreach(arg ${tbb_GBPFMA_MAKE_ARGS}) - if (arg MATCHES "tbb_build_dir=") - string(REPLACE "tbb_build_dir=" "" tbb_build_dir "${arg}") - elseif (arg MATCHES "tbb_build_prefix=") - string(REPLACE "tbb_build_prefix=" "" tbb_build_prefix "${arg}") - endif() - endforeach() - - set(tbb_release_dir "${tbb_build_dir}/${tbb_build_prefix}_release") - set(tbb_debug_dir "${tbb_build_dir}/${tbb_build_prefix}_debug") - - file(TO_CMAKE_PATH "${tbb_release_dir}" tbb_release_dir) - file(TO_CMAKE_PATH "${tbb_debug_dir}" tbb_debug_dir) - - set(${tbb_GBPFMA_RELEASE_DIR} ${tbb_release_dir} PARENT_SCOPE) - set(${tbb_GBPFMA_DEBUG_DIR} ${tbb_debug_dir} PARENT_SCOPE) - endfunction() - - # -------------------- # - # Function entry point # - # -------------------- # - set(oneValueArgs TBB_ROOT CONFIG_DIR) - set(multiValueArgs MAKE_ARGS) - cmake_parse_arguments(tbb_build "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if (NOT EXISTS "${tbb_build_TBB_ROOT}/Makefile" OR NOT EXISTS "${tbb_build_TBB_ROOT}/src") - message(STATUS "Intel TBB can not be built: Makefile or src directory was not found in ${tbb_build_TBB_ROOT}") - set(${tbb_build_CONFIG_DIR} ${tbb_build_CONFIG_DIR}-NOTFOUND PARENT_SCOPE) - return() - endif() - - set(make_tool_name make) - if (CMAKE_SYSTEM_NAME MATCHES "Windows") - set(make_tool_name gmake) - elseif (CMAKE_SYSTEM_NAME MATCHES "Android") - set(make_tool_name ndk-build) - endif() - - find_program(TBB_MAKE_TOOL ${make_tool_name} DOC "Make-tool to build Intel TBB.") - mark_as_advanced(TBB_MAKE_TOOL) - - if (NOT TBB_MAKE_TOOL) - message(STATUS "Intel TBB can not be built: required make-tool (${make_tool_name}) was not found") - set(${tbb_build_CONFIG_DIR} ${tbb_build_CONFIG_DIR}-NOTFOUND PARENT_SCOPE) - return() - endif() - - tbb_get_make_args(USER_DEFINED_ARGS ${tbb_build_MAKE_ARGS} RESULT tbb_make_args) - - set(tbb_build_cmd ${TBB_MAKE_TOOL} ${tbb_make_args}) - - string(REPLACE ";" " " tbb_build_cmd_str "${tbb_build_cmd}") - message(STATUS "Building Intel TBB: ${tbb_build_cmd_str}") - execute_process(COMMAND ${tbb_build_cmd} - WORKING_DIRECTORY ${tbb_build_TBB_ROOT} - RESULT_VARIABLE tbb_build_result - ERROR_VARIABLE tbb_build_error_output - OUTPUT_QUIET) - - if (NOT tbb_build_result EQUAL 0) - message(STATUS "Building is unsuccessful (${tbb_build_result}): ${tbb_build_error_output}") - set(${tbb_build_CONFIG_DIR} ${tbb_build_CONFIG_DIR}-NOTFOUND PARENT_SCOPE) - return() - endif() - - tbb_get_build_paths_from_make_args(MAKE_ARGS ${tbb_make_args} - RELEASE_DIR tbb_release_dir - DEBUG_DIR tbb_debug_dir) - - include(${_tbb_cmake_module_path}/TBBMakeConfig.cmake) - tbb_make_config(TBB_ROOT ${tbb_build_TBB_ROOT} - SYSTEM_NAME ${CMAKE_SYSTEM_NAME} - CONFIG_DIR tbb_config_dir - CONFIG_FOR_SOURCE - TBB_RELEASE_DIR ${tbb_release_dir} - TBB_DEBUG_DIR ${tbb_debug_dir}) - - set(${tbb_build_CONFIG_DIR} ${tbb_config_dir} PARENT_SCOPE) -endfunction() diff --git a/cmake/modules/TBBGet.cmake b/cmake/modules/TBBGet.cmake deleted file mode 100644 index 87872931c..000000000 --- a/cmake/modules/TBBGet.cmake +++ /dev/null @@ -1,294 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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(CMakeParseArguments) - -# Save the location of Intel TBB CMake modules here, as it will not be possible to do inside functions, -# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html -set(_tbb_cmake_module_path ${CMAKE_CURRENT_LIST_DIR}) - -## -# Downloads file. -# -# Parameters: -# URL - URL to download data from; -# SAVE_AS - filename there to save downloaded data; -# INFO - text description of content to be downloaded; -# will be printed as message in format is "Downloading : ; -# FORCE - option to delete local file from SAVE_AS if it exists; -# -function(_tbb_download_file) - set(options FORCE) - set(oneValueArgs URL RELEASE SAVE_AS INFO) - cmake_parse_arguments(tbb_df "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if (tbb_df_FORCE AND EXISTS "${tbb_df_SAVE_AS}") - file(REMOVE ${tbb_df_SAVE_AS}) - endif() - - if (NOT EXISTS "${tbb_df_SAVE_AS}") - set(_show_progress) - if (TBB_DOWNLOADING_PROGRESS) - set(_show_progress SHOW_PROGRESS) - endif() - - message(STATUS "Downloading ${tbb_df_INFO}: ${tbb_df_URL}") - file(DOWNLOAD ${tbb_df_URL} ${tbb_df_SAVE_AS} ${_show_progress} STATUS download_status) - - list(GET download_status 0 download_status_num) - if (NOT download_status_num EQUAL 0) - message(STATUS "Unsuccessful downloading: ${download_status}") - file(REMOVE ${tbb_df_SAVE_AS}) - return() - endif() - else() - message(STATUS "Needed file was found locally ${tbb_df_SAVE_AS}. Remove it if you still want to download a new one") - endif() -endfunction() - -## -# Checks if specified Intel TBB release is available on GitHub. -# -# tbb_check_git_release( ) -# Parameters: -# - release to be checked; -# - store result (TRUE/FALSE). -# -function(_tbb_check_git_release_tag _tbb_release_tag _tbb_release_tag_avail) - if (_tbb_release_tag STREQUAL LATEST) - set(${_tbb_release_tag_avail} TRUE PARENT_SCOPE) - return() - endif() - - set(tbb_releases_file "${CMAKE_CURRENT_BINARY_DIR}/tbb_releases.json") - - _tbb_download_file(URL "${tbb_github_api}/releases" - SAVE_AS ${tbb_releases_file} - INFO "information from GitHub about Intel TBB releases" - FORCE) - - if (NOT EXISTS "${tbb_releases_file}") - set(${_tbb_release_tag_avail} FALSE PARENT_SCOPE) - return() - endif() - - file(READ ${tbb_releases_file} tbb_releases) - - string(REPLACE "\"" "" tbb_releases ${tbb_releases}) - string(REGEX MATCHALL "tag_name: *([A-Za-z0-9_\\.]+)" tbb_releases ${tbb_releases}) - - set(_release_available FALSE) - foreach(tbb_rel ${tbb_releases}) - string(REGEX REPLACE "tag_name: *" "" tbb_rel_cut ${tbb_rel}) - list(REMOVE_ITEM tbb_releases ${tbb_rel}) - list(APPEND tbb_releases ${tbb_rel_cut}) - if (_tbb_release_tag STREQUAL tbb_rel_cut) - set(_release_available TRUE) - break() - endif() - endforeach() - - if (NOT _release_available) - string(REPLACE ";" ", " tbb_releases_str "${tbb_releases}") - message(STATUS "Requested release tag ${_tbb_release_tag} is not available. Available Intel TBB release tags: ${tbb_releases_str}") - endif() - - set(${_tbb_release_tag_avail} ${_release_available} PARENT_SCOPE) -endfunction() - -## -# Compares two Intel TBB releases and provides result -# TRUE if the first release is less than the second, FALSE otherwise. -# -# tbb_is_release_less( ) -# -function(_tbb_is_release_less rel1 rel2 result) - # Convert release to numeric representation to compare it using "if" with VERSION_LESS. - string(REGEX REPLACE "[A-Za-z]" "" rel1 "${rel1}") - string(REPLACE "_" "." rel1 "${rel1}") - string(REGEX REPLACE "[A-Za-z]" "" rel2 "${rel2}") - string(REPLACE "_" "." rel2 "${rel2}") - - if (${rel1} VERSION_LESS ${rel2}) - set(${result} TRUE PARENT_SCOPE) - return() - endif() - - set(${result} FALSE PARENT_SCOPE) -endfunction() - -## -# Finds exact URL to download Intel TBB basing on provided parameters. -# -# Usage: -# _tbb_get_url(URL RELEASE_TAG OS [SOURCE_CODE]) -# -function(_tbb_get_url) - set(oneValueArgs URL RELEASE_TAG OS) - set(options SOURCE_CODE) - cmake_parse_arguments(tbb_get_url "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - set(tbb_github_api "https://api.github.com/repos/01org/tbb") - - _tbb_check_git_release_tag(${tbb_get_url_RELEASE_TAG} tbb_release_available) - if (NOT tbb_release_available) - set(${tbb_download_FULL_PATH} ${tbb_download_FULL_PATH}-NOTFOUND PARENT_SCOPE) - return() - endif() - - if (tbb_get_url_RELEASE_TAG STREQUAL LATEST) - set(tbb_rel_info_api_url "${tbb_github_api}/releases/latest") - else() - set(tbb_rel_info_api_url "${tbb_github_api}/releases/tags/${tbb_get_url_RELEASE_TAG}") - endif() - - set(tbb_release_info_file "${CMAKE_CURRENT_BINARY_DIR}/tbb_${tbb_get_url_RELEASE_TAG}_info.json") - - _tbb_download_file(URL ${tbb_rel_info_api_url} - SAVE_AS ${tbb_release_info_file} - INFO "information from GitHub about packages for Intel TBB ${tbb_get_url_RELEASE_TAG}" - FORCE) - - if (NOT EXISTS "${tbb_release_info_file}") - set(${tbb_get_url_URL} ${tbb_get_url_URL}-NOTFOUND PARENT_SCOPE) - return() - endif() - - file(STRINGS ${tbb_release_info_file} tbb_release_info) - - if (tbb_get_url_SOURCE_CODE) - # Find name of the latest release to get link to source archive. - if (tbb_get_url_RELEASE_TAG STREQUAL LATEST) - string(REPLACE "\"" "" tbb_release_info ${tbb_release_info}) - string(REGEX REPLACE ".*tag_name: *([A-Za-z0-9_\\.]+).*" "\\1" tbb_get_url_RELEASE_TAG "${tbb_release_info}") - endif() - - set(${tbb_get_url_URL} "https://github.com/01org/tbb/archive/${tbb_get_url_RELEASE_TAG}.tar.gz" PARENT_SCOPE) - else() - if (tbb_get_url_OS MATCHES "Linux") - set(tbb_lib_archive_suffix lin.tgz) - elseif (tbb_get_url_OS MATCHES "Windows") - set(tbb_lib_archive_suffix win.zip) - elseif (tbb_get_url_OS MATCHES "Darwin") - set(tbb_lib_archive_suffix mac.tgz) - - # Since 2017_U4 release archive for Apple has suffix "mac.tgz" instead of "osx.tgz". - if (NOT tbb_get_url_RELEASE_TAG STREQUAL "LATEST") - _tbb_is_release_less(${tbb_get_url_RELEASE_TAG} 2017_U4 release_less) - if (release_less) - set(tbb_lib_archive_suffix osx.tgz) - endif() - endif() - elseif (tbb_get_url_OS MATCHES "Android") - set(tbb_lib_archive_suffix and.tgz) - else() - message(STATUS "Currently prebuilt Intel TBB is not available for your OS (${tbb_get_url_OS})") - set(${tbb_get_url_URL} ${tbb_get_url_URL}-NOTFOUND PARENT_SCOPE) - return() - endif() - - string(REGEX REPLACE ".*(https.*oss_${tbb_lib_archive_suffix}).*" "\\1" tbb_bin_url "${tbb_release_info}") - - set(${tbb_get_url_URL} ${tbb_bin_url} PARENT_SCOPE) - endif() -endfunction() - -function(tbb_get) - set(oneValueArgs RELEASE_TAG SYSTEM_NAME SAVE_TO TBB_ROOT CONFIG_DIR) - set(options SOURCE_CODE) - cmake_parse_arguments(tbb_get "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - set(tbb_os ${CMAKE_SYSTEM_NAME}) - if (tbb_get_SYSTEM_NAME) - set(tbb_os ${tbb_get_SYSTEM_NAME}) - endif() - - set(tbb_release_tag LATEST) - if (tbb_get_RELEASE_TAG) - set(tbb_release_tag ${tbb_get_RELEASE_TAG}) - endif() - - set(tbb_save_to ${CMAKE_CURRENT_BINARY_DIR}/tbb_downloaded) - if (tbb_get_SAVE_TO) - set(tbb_save_to ${tbb_get_SAVE_TO}) - endif() - - if (tbb_get_SOURCE_CODE) - _tbb_get_url(URL tbb_url RELEASE_TAG ${tbb_release_tag} OS ${tbb_os} SOURCE_CODE) - else() - _tbb_get_url(URL tbb_url RELEASE_TAG ${tbb_release_tag} OS ${tbb_os}) - endif() - - if (NOT tbb_url) - message(STATUS "URL to download Intel TBB has not been found") - set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) - return() - endif() - - get_filename_component(filename ${tbb_url} NAME) - set(local_file "${CMAKE_CURRENT_BINARY_DIR}/${filename}") - - _tbb_download_file(URL ${tbb_url} - SAVE_AS ${local_file} - INFO "Intel TBB library") - - if (NOT EXISTS "${local_file}") - set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) - return() - endif() - - get_filename_component(subdir_name ${filename} NAME_WE) - file(MAKE_DIRECTORY ${tbb_save_to}/${subdir_name}) - if (NOT EXISTS "${tbb_save_to}/${subdir_name}") - message(STATUS "${tbb_save_to}/${subdir_name} can not be created") - set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) - return() - endif() - - message(STATUS "Unpacking ${local_file} to ${tbb_save_to}/${subdir_name}") - execute_process(COMMAND ${CMAKE_COMMAND} -E tar xzf ${local_file} - WORKING_DIRECTORY ${tbb_save_to}/${subdir_name} - RESULT_VARIABLE unpacking_result) - - if (NOT unpacking_result EQUAL 0) - message(STATUS "Unsuccessful unpacking: ${unpacking_result}") - set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) - return() - endif() - - file(GLOB_RECURSE tbb_h ${tbb_save_to}/${subdir_name}/*/include/tbb/tbb.h) - list(GET tbb_h 0 tbb_h) - - if (NOT EXISTS "${tbb_h}") - message(STATUS "tbb/tbb.h has not been found in the downloaded package") - set(${tbb_get_TBB_ROOT} ${tbb_get_TBB_ROOT}-NOTFOUND PARENT_SCOPE) - return() - endif() - - get_filename_component(tbb_root "${tbb_h}" PATH) - get_filename_component(tbb_root "${tbb_root}" PATH) - get_filename_component(tbb_root "${tbb_root}" PATH) - - if (NOT tbb_get_SOURCE_CODE) - set(tbb_config_dir ${tbb_root}/cmake) - - if (NOT EXISTS "${tbb_config_dir}") - tbb_make_config(TBB_ROOT ${tbb_root} CONFIG_DIR tbb_config_dir) - endif() - - set(${tbb_get_CONFIG_DIR} ${tbb_config_dir} PARENT_SCOPE) - endif() - - set(${tbb_get_TBB_ROOT} ${tbb_root} PARENT_SCOPE) -endfunction() diff --git a/cmake/modules/TBBInstallConfig.cmake b/cmake/modules/TBBInstallConfig.cmake deleted file mode 100644 index b6ed34b0b..000000000 --- a/cmake/modules/TBBInstallConfig.cmake +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (c) 2019 Intel Corporation -# -# 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(CMakeParseArguments) - -# Save the location of Intel TBB CMake modules here, as it will not be possible to do inside functions, -# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html -set(_tbb_cmake_module_path ${CMAKE_CURRENT_LIST_DIR}) - -function(tbb_install_config) - set(oneValueArgs INSTALL_DIR - SYSTEM_NAME - LIB_REL_PATH INC_REL_PATH BIN_REL_PATH TBB_VERSION TBB_VERSION_FILE - LIB_PATH BIN_PATH INC_PATH) # If TBB is installed on the system - - cmake_parse_arguments(tbb_IC "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - get_filename_component(config_install_dir ${tbb_IC_INSTALL_DIR} ABSOLUTE) - file(MAKE_DIRECTORY ${config_install_dir}) - - # --- TBB_LIB_REL_PATH handling --- - set(TBB_LIB_REL_PATH "../../../lib") - - if (tbb_IC_LIB_REL_PATH) - file(TO_CMAKE_PATH ${tbb_IC_LIB_REL_PATH} TBB_LIB_REL_PATH) - endif() - - if (tbb_IC_LIB_PATH) - get_filename_component(lib_abs_path ${tbb_IC_LIB_PATH} ABSOLUTE) - file(RELATIVE_PATH TBB_LIB_REL_PATH ${config_install_dir} ${lib_abs_path}) - unset(lib_abs_path) - endif() - # ------ - - # --- TBB_BIN_REL_PATH handling --- - set(TBB_BIN_REL_PATH "../../../bin") - - if (tbb_IC_BIN_REL_PATH) - file(TO_CMAKE_PATH ${tbb_IC_BIN_REL_PATH} TBB_BIN_REL_PATH) - endif() - - if (tbb_IC_BIN_PATH) - get_filename_component(bin_abs_path ${tbb_IC_BIN_PATH} ABSOLUTE) - file(RELATIVE_PATH TBB_BIN_REL_PATH ${config_install_dir} ${bin_abs_path}) - unset(bin_abs_path) - endif() - # ------ - - # --- TBB_INC_REL_PATH handling --- - set(TBB_INC_REL_PATH "../../../include") - - if (tbb_IC_INC_REL_PATH) - file(TO_CMAKE_PATH ${tbb_IC_INC_REL_PATH} TBB_INC_REL_PATH) - endif() - - if (tbb_IC_INC_PATH) - get_filename_component(inc_abs_path ${tbb_IC_INC_PATH} ABSOLUTE) - file(RELATIVE_PATH TBB_INC_REL_PATH ${config_install_dir} ${inc_abs_path}) - unset(inc_abs_path) - endif() - # ------ - - # --- TBB_VERSION handling --- - if (tbb_IC_TBB_VERSION) - set(TBB_VERSION ${tbb_IC_TBB_VERSION}) - else() - set(tbb_version_file "${config_install_dir}/${TBB_INC_REL_PATH}/tbb/tbb_stddef.h") - if (tbb_IC_TBB_VERSION_FILE) - set(tbb_version_file ${tbb_IC_TBB_VERSION_FILE}) - endif() - - file(READ ${tbb_version_file} _tbb_stddef) - string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_stddef}") - string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_stddef}") - string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" _tbb_ver_interface "${_tbb_stddef}") - set(TBB_VERSION "${_tbb_ver_major}.${_tbb_ver_minor}.${_tbb_ver_interface}") - endif() - # ------ - - set(tbb_system_name ${CMAKE_SYSTEM_NAME}) - if (tbb_IC_SYSTEM_NAME) - set(tbb_system_name ${tbb_IC_SYSTEM_NAME}) - endif() - - if (tbb_system_name STREQUAL "Linux") - set(TBB_LIB_PREFIX "lib") - set(TBB_LIB_EXT "so.2") - set(TBB_IMPLIB_RELEASE "") - set(TBB_IMPLIB_DEBUG "") - elseif (tbb_system_name STREQUAL "Darwin") - set(TBB_LIB_PREFIX "lib") - set(TBB_LIB_EXT "dylib") - set(TBB_IMPLIB_RELEASE "") - set(TBB_IMPLIB_DEBUG "") - elseif (tbb_system_name STREQUAL "Windows") - set(TBB_LIB_PREFIX "") - set(TBB_LIB_EXT "dll") - # .lib files installed to TBB_LIB_REL_PATH (e.g. /lib); - # .dll files installed to TBB_BIN_REL_PATH (e.g. /bin); - # Expand TBB_LIB_REL_PATH here in IMPORTED_IMPLIB property and - # redefine it with TBB_BIN_REL_PATH value to properly fill IMPORTED_LOCATION property in TBBConfig.cmake.in template. - set(TBB_IMPLIB_RELEASE " - IMPORTED_IMPLIB_RELEASE \"\${CMAKE_CURRENT_LIST_DIR}/${TBB_LIB_REL_PATH}/\${_tbb_component}.lib\"") - set(TBB_IMPLIB_DEBUG " - IMPORTED_IMPLIB_DEBUG \"\${CMAKE_CURRENT_LIST_DIR}/${TBB_LIB_REL_PATH}/\${_tbb_component}_debug.lib\"") - set(TBB_LIB_REL_PATH ${TBB_BIN_REL_PATH}) - else() - message(FATAL_ERROR "Unsupported OS name: ${tbb_system_name}") - endif() - - configure_file(${_tbb_cmake_module_path}/templates/TBBConfig.cmake.in ${config_install_dir}/TBBConfig.cmake @ONLY) - configure_file(${_tbb_cmake_module_path}/templates/TBBConfigVersion.cmake.in ${config_install_dir}/TBBConfigVersion.cmake @ONLY) -endfunction() diff --git a/cmake/modules/TBBMakeConfig.cmake b/cmake/modules/TBBMakeConfig.cmake deleted file mode 100644 index bbcb990b3..000000000 --- a/cmake/modules/TBBMakeConfig.cmake +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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. - -# -# Usage: -# include(TBBMakeConfig.cmake) -# tbb_make_config(TBB_ROOT SYSTEM_NAME CONFIG_DIR [SAVE_TO] [CONFIG_FOR_SOURCE TBB_RELEASE_DIR TBB_DEBUG_DIR ]) -# - -include(CMakeParseArguments) - -# Save the location of Intel TBB CMake modules here, as it will not be possible to do inside functions, -# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html -set(_tbb_cmake_module_path ${CMAKE_CURRENT_LIST_DIR}) - -function(tbb_make_config) - set(oneValueArgs TBB_ROOT SYSTEM_NAME CONFIG_DIR SAVE_TO TBB_RELEASE_DIR TBB_DEBUG_DIR) - set(options CONFIG_FOR_SOURCE) - cmake_parse_arguments(tbb_MK "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - set(tbb_system_name ${CMAKE_SYSTEM_NAME}) - if (tbb_MK_SYSTEM_NAME) - set(tbb_system_name ${tbb_MK_SYSTEM_NAME}) - endif() - - set(tbb_config_dir ${tbb_MK_TBB_ROOT}/cmake) - if (tbb_MK_SAVE_TO) - set(tbb_config_dir ${tbb_MK_SAVE_TO}) - endif() - - file(MAKE_DIRECTORY ${tbb_config_dir}) - - set(TBB_DEFAULT_COMPONENTS tbb tbbmalloc tbbmalloc_proxy) - - if (tbb_MK_CONFIG_FOR_SOURCE) - set(TBB_RELEASE_DIR ${tbb_MK_TBB_RELEASE_DIR}) - set(TBB_DEBUG_DIR ${tbb_MK_TBB_DEBUG_DIR}) - endif() - - if (tbb_system_name STREQUAL "Linux") - set(TBB_SHARED_LIB_DIR "lib") - set(TBB_X32_SUBDIR "ia32") - set(TBB_X64_SUBDIR "intel64") - set(TBB_LIB_PREFIX "lib") - set(TBB_LIB_EXT "so.2") - - # Note: multiline variable - set(TBB_CHOOSE_COMPILER_SUBDIR "if (CMAKE_CXX_COMPILER_LOADED) - set(_tbb_compiler_id \${CMAKE_CXX_COMPILER_ID}) - set(_tbb_compiler_ver \${CMAKE_CXX_COMPILER_VERSION}) -elseif (CMAKE_C_COMPILER_LOADED) - set(_tbb_compiler_id \${CMAKE_C_COMPILER_ID}) - set(_tbb_compiler_ver \${CMAKE_C_COMPILER_VERSION}) -endif() - -# For non-GCC compilers try to find version of system GCC to choose right compiler subdirectory. -if (NOT _tbb_compiler_id STREQUAL \"GNU\") - execute_process(COMMAND gcc --version OUTPUT_VARIABLE _tbb_gcc_ver_output ERROR_QUIET) - string(REGEX REPLACE \".*gcc.*([0-9]+\\\\.[0-9]+)\\\\.[0-9]+.*\" \"\\\\1\" _tbb_compiler_ver \"\${_tbb_gcc_ver_output}\") - if (NOT _tbb_compiler_ver) - message(FATAL_ERROR \"This Intel TBB package is intended to be used only in environment with available 'gcc'\") - endif() - unset(_tbb_gcc_ver_output) -endif() - -set(_tbb_compiler_subdir gcc4.1) -foreach (_tbb_gcc_version 4.1 4.4 4.7) - if (NOT _tbb_compiler_ver VERSION_LESS \${_tbb_gcc_version}) - set(_tbb_compiler_subdir gcc\${_tbb_gcc_version}) - endif() -endforeach() - -unset(_tbb_compiler_id) -unset(_tbb_compiler_ver)") - - elseif (tbb_system_name STREQUAL "Windows") - set(TBB_SHARED_LIB_DIR "bin") - set(TBB_X32_SUBDIR "ia32") - set(TBB_X64_SUBDIR "intel64") - set(TBB_LIB_PREFIX "") - set(TBB_LIB_EXT "dll") - - # Note: multiline variable - set(TBB_CHOOSE_COMPILER_SUBDIR "if (NOT MSVC) - message(FATAL_ERROR \"This Intel TBB package is intended to be used only in the project with MSVC\") -endif() - -# Detect the most relevant MSVC subdirectory -set(_tbb_msvc_1700_subdir vc11) -set(_tbb_msvc_1800_subdir vc12) -set(_tbb_msvc_1900_subdir vc14) -set(_tbb_msvc_ver \${MSVC_VERSION}) -if (MSVC_VERSION VERSION_LESS 1700) - message(FATAL_ERROR \"This Intel TBB package is intended to be used only in the project with MSVC version 1700 (vc11) or higher\") -elseif (MSVC_VERSION VERSION_GREATER 1900) - set(_tbb_msvc_ver 1900) -endif() -set(_tbb_compiler_subdir \${_tbb_msvc_\${_tbb_msvc_ver}_subdir}) -unset(_tbb_msvc_1700_subdir) -unset(_tbb_msvc_1800_subdir) -unset(_tbb_msvc_1900_subdir) - -if (WINDOWS_STORE) - set(_tbb_compiler_subdir \${_tbb_compiler_subdir}_ui) -endif()") - - if (tbb_MK_CONFIG_FOR_SOURCE) - set(TBB_IMPLIB_RELEASE " - IMPORTED_IMPLIB_RELEASE \"${tbb_MK_TBB_RELEASE_DIR}/\${_tbb_component}.lib\"") - set(TBB_IMPLIB_DEBUG " - IMPORTED_IMPLIB_DEBUG \"${tbb_MK_TBB_DEBUG_DIR}/\${_tbb_component}_debug.lib\"") - else() - set(TBB_IMPLIB_RELEASE " - IMPORTED_IMPLIB_RELEASE \"\${_tbb_root}/lib/\${_tbb_arch_subdir}/\${_tbb_compiler_subdir}/\${_tbb_component}.lib\"") - set(TBB_IMPLIB_DEBUG " - IMPORTED_IMPLIB_DEBUG \"\${_tbb_root}/lib/\${_tbb_arch_subdir}/\${_tbb_compiler_subdir}/\${_tbb_component}_debug.lib\"") - endif() - - # Note: multiline variable - # tbb/internal/_tbb_windef.h (included via tbb/tbb_stddef.h) does implicit linkage of some .lib files, use a special define to avoid it - set(TBB_COMPILE_DEFINITIONS " - INTERFACE_COMPILE_DEFINITIONS \"__TBB_NO_IMPLICIT_LINKAGE=1\"") - elseif (tbb_system_name STREQUAL "Darwin") - set(TBB_SHARED_LIB_DIR "lib") - set(TBB_X32_SUBDIR ".") - set(TBB_X64_SUBDIR ".") - set(TBB_LIB_PREFIX "lib") - set(TBB_LIB_EXT "dylib") - set(TBB_CHOOSE_COMPILER_SUBDIR "set(_tbb_compiler_subdir .)") - elseif (tbb_system_name STREQUAL "Android") - set(TBB_SHARED_LIB_DIR "lib") - set(TBB_X32_SUBDIR ".") - set(TBB_X64_SUBDIR "x86_64") - set(TBB_LIB_PREFIX "lib") - set(TBB_LIB_EXT "so") - set(TBB_CHOOSE_COMPILER_SUBDIR "set(_tbb_compiler_subdir .)") - else() - message(FATAL_ERROR "Unsupported OS name: ${tbb_system_name}") - endif() - - file(READ "${tbb_MK_TBB_ROOT}/include/tbb/tbb_stddef.h" _tbb_stddef) - string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_stddef}") - string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_stddef}") - string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_tbb_stddef}") - set(TBB_VERSION "${_tbb_ver_major}.${_tbb_ver_minor}.${TBB_INTERFACE_VERSION}") - - if (tbb_MK_CONFIG_FOR_SOURCE) - set(TBB_CHOOSE_ARCH_AND_COMPILER "") - set(TBB_RELEASE_LIB_PATH "${TBB_RELEASE_DIR}") - set(TBB_DEBUG_LIB_PATH "${TBB_DEBUG_DIR}") - set(TBB_UNSET_ADDITIONAL_VARIABLES "") - else() - # Note: multiline variable - set(TBB_CHOOSE_ARCH_AND_COMPILER " -if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(_tbb_arch_subdir ${TBB_X64_SUBDIR}) -else() - set(_tbb_arch_subdir ${TBB_X32_SUBDIR}) -endif() - -${TBB_CHOOSE_COMPILER_SUBDIR} - -get_filename_component(_tbb_lib_path \"\${_tbb_root}/${TBB_SHARED_LIB_DIR}/\${_tbb_arch_subdir}/\${_tbb_compiler_subdir}\" ABSOLUTE) -") - - set(TBB_RELEASE_LIB_PATH "\${_tbb_lib_path}") - set(TBB_DEBUG_LIB_PATH "\${_tbb_lib_path}") - - # Note: multiline variable - set(TBB_UNSET_ADDITIONAL_VARIABLES " -unset(_tbb_arch_subdir) -unset(_tbb_compiler_subdir)") - endif() - - configure_file(${_tbb_cmake_module_path}/templates/TBBConfigInternal.cmake.in ${tbb_config_dir}/TBBConfig.cmake @ONLY) - configure_file(${_tbb_cmake_module_path}/templates/TBBConfigVersion.cmake.in ${tbb_config_dir}/TBBConfigVersion.cmake @ONLY) - - set(${tbb_MK_CONFIG_DIR} ${tbb_config_dir} PARENT_SCOPE) -endfunction() diff --git a/cmake/modules/tbb_config_generator.cmake b/cmake/modules/tbb_config_generator.cmake deleted file mode 100644 index 3f94efd18..000000000 --- a/cmake/modules/tbb_config_generator.cmake +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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(tbb_conf_gen_print_help) - message("Usage: cmake -DTBB_ROOT= -DTBB_OS=Linux|Windows|Darwin [-DSAVE_TO=] -P tbb_config_generator.cmake") -endfunction() - -if (NOT DEFINED TBB_ROOT) - tbb_conf_gen_print_help() - message(FATAL_ERROR "Required parameter TBB_ROOT is not defined") -endif() - -if (NOT EXISTS "${TBB_ROOT}") - tbb_conf_gen_print_help() - message(FATAL_ERROR "TBB_ROOT=${TBB_ROOT} does not exist") -endif() - -if (NOT DEFINED TBB_OS) - tbb_conf_gen_print_help() - message(FATAL_ERROR "Required parameter TBB_OS is not defined") -endif() - -if (DEFINED SAVE_TO) - set(tbb_conf_gen_save_to_param SAVE_TO ${SAVE_TO}) -endif() - -include(${CMAKE_CURRENT_LIST_DIR}/TBBMakeConfig.cmake) -tbb_make_config(TBB_ROOT ${TBB_ROOT} CONFIG_DIR tbb_config_dir SYSTEM_NAME ${TBB_OS} ${tbb_conf_gen_save_to_param}) - -message(STATUS "TBBConfig files were created in ${tbb_config_dir}") diff --git a/cmake/modules/tbb_config_installer.cmake b/cmake/modules/tbb_config_installer.cmake deleted file mode 100644 index fa165e8e1..000000000 --- a/cmake/modules/tbb_config_installer.cmake +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2019 Intel Corporation -# -# 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(tbb_conf_gen_print_help) - message("Usage: cmake -DINSTALL_DIR= -DSYSTEM_NAME=Linux|Darwin|Windows -P tbb_config_generator.cmake - -Parameters: - For custom TBB package: - -DTBB_VERSION_FILE= - -DTBB_VERSION=.. (alternative to TBB_VERSION_FILE) - -DINC_REL_PATH= - -DLIB_REL_PATH= - -DBIN_REL_PATH= (only for Windows) - For installed TBB: - -DINC_PATH= - -DLIB_PATH= - -DBIN_PATH= (only for Windows) -") -endfunction() - -if (NOT DEFINED INSTALL_DIR) - tbb_conf_gen_print_help() - message(FATAL_ERROR "Required parameter INSTALL_DIR is not defined") -endif() - -if (NOT DEFINED SYSTEM_NAME) - tbb_conf_gen_print_help() - message(FATAL_ERROR "Required parameter SYSTEM_NAME is not defined") -endif() - -foreach (arg TBB_VERSION INC_REL_PATH LIB_REL_PATH BIN_REL_PATH TBB_VERSION_FILE INC_PATH LIB_PATH BIN_PATH) - set(optional_args ${optional_args} ${arg} ${${arg}}) -endforeach() - -include(${CMAKE_CURRENT_LIST_DIR}/TBBInstallConfig.cmake) -tbb_install_config(INSTALL_DIR ${INSTALL_DIR} SYSTEM_NAME ${SYSTEM_NAME} ${optional_args}) -message(STATUS "TBBConfig files were created in ${INSTALL_DIR}") diff --git a/cmake/modules/templates/TBBConfig.cmake.in b/cmake/modules/templates/TBBConfig.cmake.in deleted file mode 100644 index 84e25399f..000000000 --- a/cmake/modules/templates/TBBConfig.cmake.in +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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. - -# It defines the following variables: -# TBB_tbb_FOUND -# TBB_tbbmalloc_FOUND -# TBB_tbbmalloc_proxy_FOUND -# TBB_IMPORTED_TARGETS -# -# TBBConfigVersion.cmake defines TBB_VERSION -# -# Initialize to default values -if (NOT TBB_tbb_FOUND) - set(TBB_tbb_FOUND 0) -endif() -if (NOT TBB_tbbmalloc_FOUND) - set(TBB_tbbmalloc_FOUND 0) -endif() -if (NOT TBB_tbbmalloc_proxy_FOUND) - set(TBB_tbbmalloc_proxy_FOUND 0) -endif() -if (NOT TBB_IMPORTED_TARGETS) - set(TBB_IMPORTED_TARGETS "") -endif() - -if (NOT TBB_FIND_COMPONENTS) - set(TBB_FIND_COMPONENTS "tbb;tbbmalloc;tbbmalloc_proxy") - foreach (_tbb_component ${TBB_FIND_COMPONENTS}) - set(TBB_FIND_REQUIRED_${_tbb_component} 1) - endforeach() -endif() - -# Add components with internal dependencies: tbbmalloc_proxy -> tbbmalloc -list(FIND TBB_FIND_COMPONENTS tbbmalloc_proxy _tbbmalloc_proxy_ix) -if (NOT _tbbmalloc_proxy_ix EQUAL -1) - list(FIND TBB_FIND_COMPONENTS tbbmalloc _tbbmalloc_ix) - if (_tbbmalloc_ix EQUAL -1) - list(APPEND TBB_FIND_COMPONENTS tbbmalloc) - set(TBB_FIND_REQUIRED_tbbmalloc ${TBB_FIND_REQUIRED_tbbmalloc_proxy}) - endif() - unset(_tbbmalloc_ix) -endif() -unset(_tbbmalloc_proxy_ix) - -foreach (_tbb_component ${TBB_FIND_COMPONENTS}) - set(_tbb_release_lib "${CMAKE_CURRENT_LIST_DIR}/@TBB_LIB_REL_PATH@/@TBB_LIB_PREFIX@${_tbb_component}.@TBB_LIB_EXT@") - set(_tbb_debug_lib "${CMAKE_CURRENT_LIST_DIR}/@TBB_LIB_REL_PATH@/@TBB_LIB_PREFIX@${_tbb_component}_debug.@TBB_LIB_EXT@") - - if (EXISTS "${_tbb_release_lib}" OR EXISTS "${_tbb_debug_lib}") - if (NOT TARGET TBB::${_tbb_component}) - add_library(TBB::${_tbb_component} SHARED IMPORTED) - set_target_properties(TBB::${_tbb_component} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_LIST_DIR}/@TBB_INC_REL_PATH@") - - if (EXISTS "${_tbb_release_lib}") - set_target_properties(TBB::${_tbb_component} PROPERTIES - IMPORTED_LOCATION_RELEASE "${_tbb_release_lib}"@TBB_IMPLIB_RELEASE@) - set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - endif() - - if (EXISTS "${_tbb_debug_lib}") - set_target_properties(TBB::${_tbb_component} PROPERTIES - IMPORTED_LOCATION_DEBUG "${_tbb_debug_lib}"@TBB_IMPLIB_DEBUG@) - set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - endif() - - # Add internal dependencies for imported targets: TBB::tbbmalloc_proxy -> TBB::tbbmalloc - if (_tbb_component STREQUAL tbbmalloc_proxy) - set_target_properties(TBB::tbbmalloc_proxy PROPERTIES INTERFACE_LINK_LIBRARIES TBB::tbbmalloc) - endif() - list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component}) - else() - message(STATUS "Using previously found TBB::${_tbb_component}") - endif() - set(TBB_${_tbb_component}_FOUND 1) - elseif (TBB_FIND_REQUIRED AND TBB_FIND_REQUIRED_${_tbb_component}) - message(STATUS "Missed required Intel TBB component: ${_tbb_component}") - message(STATUS " one or both of:\n ${_tbb_release_lib}\n ${_tbb_debug_lib}\n files must exist.") - set(TBB_FOUND FALSE) - set(TBB_${_tbb_component}_FOUND 0) - endif() -endforeach() -unset(_tbb_release_lib) -unset(_tbb_debug_lib) diff --git a/cmake/modules/templates/TBBConfigInternal.cmake.in b/cmake/modules/templates/TBBConfigInternal.cmake.in deleted file mode 100644 index 40528c6df..000000000 --- a/cmake/modules/templates/TBBConfigInternal.cmake.in +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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. - -# TBB_FOUND should not be set explicitly. It is defined automatically by CMake. -# Handling of TBB_VERSION is in TBBConfigVersion.cmake. - -if (NOT TBB_FIND_COMPONENTS) - set(TBB_FIND_COMPONENTS "@TBB_DEFAULT_COMPONENTS@") - foreach (_tbb_component ${TBB_FIND_COMPONENTS}) - set(TBB_FIND_REQUIRED_${_tbb_component} 1) - endforeach() -endif() - -# Add components with internal dependencies: tbbmalloc_proxy -> tbbmalloc -list(FIND TBB_FIND_COMPONENTS tbbmalloc_proxy _tbbmalloc_proxy_ix) -if (NOT _tbbmalloc_proxy_ix EQUAL -1) - list(FIND TBB_FIND_COMPONENTS tbbmalloc _tbbmalloc_ix) - if (_tbbmalloc_ix EQUAL -1) - list(APPEND TBB_FIND_COMPONENTS tbbmalloc) - set(TBB_FIND_REQUIRED_tbbmalloc ${TBB_FIND_REQUIRED_tbbmalloc_proxy}) - endif() -endif() - -set(TBB_INTERFACE_VERSION @TBB_INTERFACE_VERSION@) - -get_filename_component(_tbb_root "${CMAKE_CURRENT_LIST_FILE}" PATH) -get_filename_component(_tbb_root "${_tbb_root}" PATH) -@TBB_CHOOSE_ARCH_AND_COMPILER@ -foreach (_tbb_component ${TBB_FIND_COMPONENTS}) - set(_tbb_release_lib "@TBB_RELEASE_LIB_PATH@/@TBB_LIB_PREFIX@${_tbb_component}.@TBB_LIB_EXT@") - set(_tbb_debug_lib "@TBB_DEBUG_LIB_PATH@/@TBB_LIB_PREFIX@${_tbb_component}_debug.@TBB_LIB_EXT@") - - if (EXISTS "${_tbb_release_lib}" OR EXISTS "${_tbb_debug_lib}") - add_library(TBB::${_tbb_component} SHARED IMPORTED) - set_target_properties(TBB::${_tbb_component} PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${_tbb_root}/include"@TBB_COMPILE_DEFINITIONS@) - - if (EXISTS "${_tbb_release_lib}") - set_target_properties(TBB::${_tbb_component} PROPERTIES - IMPORTED_LOCATION_RELEASE "${_tbb_release_lib}"@TBB_IMPLIB_RELEASE@) - set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - endif() - - if (EXISTS "${_tbb_debug_lib}") - set_target_properties(TBB::${_tbb_component} PROPERTIES - IMPORTED_LOCATION_DEBUG "${_tbb_debug_lib}"@TBB_IMPLIB_DEBUG@) - set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - endif() - - # Add internal dependencies for imported targets: TBB::tbbmalloc_proxy -> TBB::tbbmalloc - if (_tbb_component STREQUAL tbbmalloc_proxy) - set_target_properties(TBB::tbbmalloc_proxy PROPERTIES INTERFACE_LINK_LIBRARIES TBB::tbbmalloc) - endif() - - list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component}) - set(TBB_${_tbb_component}_FOUND 1) - elseif (TBB_FIND_REQUIRED AND TBB_FIND_REQUIRED_${_tbb_component}) - message(STATUS "Missed required Intel TBB component: ${_tbb_component}") - set(TBB_FOUND FALSE) - set(TBB_${_tbb_component}_FOUND 0) - endif() -endforeach() -@TBB_UNSET_ADDITIONAL_VARIABLES@ -unset(_tbbmalloc_proxy_ix) -unset(_tbbmalloc_ix) -unset(_tbb_lib_path) -unset(_tbb_release_lib) -unset(_tbb_debug_lib) diff --git a/cmake/modules/templates/TBBConfigVersion.cmake.in b/cmake/modules/templates/TBBConfigVersion.cmake.in deleted file mode 100644 index 2e31c80ed..000000000 --- a/cmake/modules/templates/TBBConfigVersion.cmake.in +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2017-2019 Intel Corporation -# -# 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(PACKAGE_VERSION @TBB_VERSION@) - -if ("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_COMPATIBLE FALSE) -else() - set(PACKAGE_VERSION_COMPATIBLE TRUE) - if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}") - set(PACKAGE_VERSION_EXACT TRUE) - endif() -endif() diff --git a/lib/libmtkahypar.pc.in b/cmake/mtkahypar.pc.in similarity index 68% rename from lib/libmtkahypar.pc.in rename to cmake/mtkahypar.pc.in index 5ade0ad68..eb0e1a574 100644 --- a/lib/libmtkahypar.pc.in +++ b/cmake/mtkahypar.pc.in @@ -1,6 +1,5 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ Name: @PROJECT_NAME@ @@ -11,4 +10,4 @@ URL: @PROJECT_URL@ Requires: Libs: -L${libdir} -lmtkahypar -Cflags: -I${includedir} \ No newline at end of file +Cflags: -I${includedir} diff --git a/codestyle/analyze-source.pl b/codestyle/analyze-source.pl deleted file mode 100644 index 094daec7e..000000000 --- a/codestyle/analyze-source.pl +++ /dev/null @@ -1,364 +0,0 @@ -#!/usr/bin/perl -w -################################################################################ -# misc/analyze-source.pl -# -# Copyright (C) 2014-2015 Timo Bingmann -# -# This program is free software: you can redistribute it and/or modify it under -# the terms of the GNU General Public License as published by the Free Software -# Foundation, either version 3 of the License, or (at your option) any later -# version. -# -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS -# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more -# details. -# -# You should have received a copy of the GNU General Public License along with -# this program. If not, see . -################################################################################ - -# print multiple email addresses -my $email_multimap = 0; - -# launch emacsen for each error -my $launch_emacs = 0; - -# write changes to files (dangerous!) -my $write_changes = 0; - -# analyze all source files instead of only modified files -my $all_files = 0; - -# function testing whether to uncrustify a path -sub filter_uncrustify($) { - my ($path) = @_; - - return 1; -} - -# get path to codestyle directory -use Cwd 'abs_path'; -my $codestyle_path = abs_path($0); -$codestyle_path =~ s/analyze-source.pl//; - -use strict; -use warnings; -use Text::Diff; -use File::stat; - -my %includemap; -my %authormap; - -my @source_filelist; - -sub expect_error($$$$) { - my ($path,$ln,$str,$expect) = @_; - - print("Bad header line $ln in $path\n"); - print("Expected $expect\n"); - print("Got $str\n"); - - system("emacsclient -n $path") if $launch_emacs; -} - -sub expect($$\@$) { - my ($path,$ln,$data,$expect) = @_; - - if ($$data[$ln] ne $expect) { - expect_error($path,$ln,$$data[$ln],$expect); - # insert line with expected value - splice(@$data, $ln, 0, $expect); - } -} -sub expectr($$\@$$) { - my ($path,$ln,$data,$expect,$replace_regex) = @_; - - if ($$data[$ln] ne $expect) { - expect_error($path,$ln,$$data[$ln],$expect); - # replace line with expected value if like regex - if ($$data[$ln] =~ m/$replace_regex/) { - $$data[$ln] = $expect; - } else { - splice(@$data, $ln, 0, $expect); - } - } -} - -sub expect_re($$\@$) { - my ($path,$ln,$data,$expect) = @_; - - if ($$data[$ln] !~ m/$expect/) { - expect_error($path, $ln, $$data[$ln], "/$expect/"); - } -} - -# check equality of two arrays -sub array_equal { - my ($a1ref,$a2ref) = @_; - - my @a1 = @{$a1ref}; - my @a2 = @{$a2ref}; - - return 0 if scalar(@a1) != scalar(@a2); - - for my $i (0..scalar(@a1)-1) { - return 0 if $a1[$i] ne $a2[$i]; - } - - return 1; -} - -# run $text through a external pipe (@program) -sub filter_program { - my $text = shift; - my @program = @_; - - # fork and read output - my $child1 = open(my $fh, "-|") // die("$0: fork: $!"); - if ($child1 == 0) { - # fork and print text - my $child2 = open(STDIN, "-|") // die("$0: fork: $!"); - if ($child2 == 0) { - print $text; - exit; - } - else { - exec(@program) or die("$0: exec: $!"); - } - } - else { - my @output = <$fh>; - close($fh) or warn("$0: close: $!"); - return @output; - } -} - -sub process_cpp { - my ($path) = @_; - - # check permissions - my $st = stat($path) or die("Cannot stat() file $path: $!"); - if ($st->mode & 0133) { - print("Wrong mode ".sprintf("%o", $st->mode)." on $path\n"); - if ($write_changes) { - chmod(0644, $path) or die("Cannot chmod() file $path: $!"); - } - } - - # read file - open(F, $path) or die("Cannot read file $path: $!"); - my @data = ; - close(F); - - push(@source_filelist, $path); - - my @origdata = @data; - - # put all #include lines into the includemap - foreach my $ln (@data) - { - if ($ln =~ m!\s*#\s*include\s*([<"]\S+[">])!) { - $includemap{$1}{$path} = 1; - } - } - - # run uncrustify if in filter - if (filter_uncrustify($path)) - { - my $data = join("", @data); - @data = filter_program($data, "uncrustify", "-q", "-c", $codestyle_path."uncrustify.cfg", "-l", "CPP"); - } - - return if array_equal(\@data, \@origdata); - - print "$path\n"; - print diff(\@origdata, \@data); - #system("emacsclient -n $path"); - - if ($write_changes) - { - open(F, "> $path") or die("Cannot write $path: $!"); - print(F join("", @data)); - close(F); - } -} - -sub process_pl_cmake { - my ($path) = @_; - - # check permissions - if ($path !~ /\.pl$/) { - my $st = stat($path) or die("Cannot stat() file $path: $!"); - if ($st->mode & 0133) { - print("Wrong mode ".sprintf("%o", $st->mode)." on $path\n"); - if ($write_changes) { - chmod(0644, $path) or die("Cannot chmod() file $path: $!"); - } - } - } - - # read file - open(F, $path) or die("Cannot read file $path: $!"); - my @data = ; - close(F); - - my @origdata = @data; - - # check source header - my $i = 0; - if ($data[$i] =~ m/#!/) { ++$i; } # bash line - expect($path, $i, @data, ('#'x80)."\n"); ++$i; - expect($path, $i, @data, "# $path\n"); ++$i; - expect($path, $i, @data, "#\n"); ++$i; - - # skip over comment - while ($data[$i] ne ('#'x80)."\n") { - expect_re($path, $i, @data, '^#( .*)?\n$'); - return unless ++$i < @data; - } - - expect($path, $i, @data, ('#'x80)."\n"); ++$i; - - # check terminating ####### comment - { - my $n = scalar(@data)-1; - if ($data[$n] !~ m!^#{80}$!) { - push(@data, "\n"); - push(@data, ("#"x80)."\n"); - } - } - - return if array_equal(\@data, \@origdata); - - print "$path\n"; - print diff(\@origdata, \@data); - #system("emacsclient -n $path"); - - if ($write_changes) - { - open(F, "> $path") or die("Cannot write $path: $!"); - print(F join("", @data)); - close(F); - } -} - -### Main ### - -foreach my $arg (@ARGV) { - if ($arg eq "-w") { $write_changes = 1; } - elsif ($arg eq "-e") { $launch_emacs = 1; } - elsif ($arg eq "-m") { $email_multimap = 1; } - elsif ($arg eq "-a") {$all_files = 1;} - elsif ($arg eq "-aw") {$all_files = 1; $write_changes = 1;} - else { - print "Unknown parameter: $arg\n"; - } -} -# check uncrustify's version: -#my ($uncrustver) = filter_program("", "uncrustify", "--version"); -#($uncrustver eq "uncrustify 0.61\n") or die("Requires uncrustify 0.61 to run correctly. "); - -my @filelist; - -if ($all_files) { - use File::Find; - find(sub { !-d && push(@filelist, $File::Find::name) }, "../."); -} else { - foreach (split /\n+/, `git status`) { - next unless /modified:|file:/; - next if /untracked/; - s/ modified: //; - s/ new file: //; - push(@filelist, "./" . $_); - } -} - -foreach my $file (@filelist) -{ - $file =~ s!./!! or die("File does not start ./"); - if ($file =~ m!^b!) { - } - elsif ($file =~ m!external|external_tools|.git|cmake|codestyle/!) { - # skip external libraries and non-code project dirs - } - elsif ($file =~ m!release.*|debug|profile/!) { - # skip build dirs - } - elsif ($file =~ m!^patches/!) { - # skip patch dir - } - elsif ($file =~ /^doc\//) { - process_cpp($file); - } - elsif ($file =~ /.*\.(h|cc|hpp|h.in)$/) { - process_cpp($file); - } - elsif ($file =~ /\.(pl|pro)$/) { - process_pl_cmake($file); - } - elsif ($file =~ m!(^|/)CMakeLists\.txt$!) { - # process_pl_cmake($file); - } - # recognize further files - elsif ($file =~ m!^\.git/!) { - } - elsif ($file =~ m!^misc/!) { - } - elsif ($file =~ m!CPPLINT\.cfg$!) { - } - elsif ($file =~ m!^doxygen-html/!) { - } - elsif ($file =~ m!^tests/.*\.(dat|plot)$!) { - # data files of tests - } - # skip all additional files in source root - elsif ($file =~ m!^[^/]+$!) { - } - else { - print "Unknown file type $file\n"; - } -} - -# print includes to includemap.txt -if (0) -{ - print "Writing includemap:\n"; - foreach my $inc (sort keys %includemap) - { - print "$inc => ".scalar(keys %{$includemap{$inc}})." ["; - print join(",", sort keys %{$includemap{$inc}}). "]\n"; - } -} - -# check includemap for C-style headers -{ - - my @cheaders = qw(assert.h ctype.h errno.h fenv.h float.h inttypes.h - limits.h locale.h math.h signal.h stdarg.h stddef.h - stdlib.h stdio.h string.h time.h); - - foreach my $ch (@cheaders) - { - $ch = "<$ch>"; - next if !$includemap{$ch}; - print "Replace c-style header $ch in\n"; - print " [".join(",", sort keys %{$includemap{$ch}}). "]\n"; - } -} - -# run cpplint.py -{ - my @lintlist; - - foreach my $path (@source_filelist) - { - #next if $path =~ /exclude/; - - push(@lintlist, $path); - } - - system($codestyle_path."cpplint.py", "--counting=total", "--extensions=h,c,cc,hpp,cpp", "--filter=-build/header_guard", @lintlist); -} - -################################################################################ diff --git a/codestyle/cpplint.py b/codestyle/cpplint.py deleted file mode 100755 index bb032a34d..000000000 --- a/codestyle/cpplint.py +++ /dev/null @@ -1,4753 +0,0 @@ -#!/usr/bin/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. - -"""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 math # for log -import os -import re -import sre_compile -import string -import sys -import unicodedata - - -_USAGE = """ -Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] - [--counting=total|toplevel|detailed] [--root=subdir] - [--linelength=digits] - [file] ... - - The style guidelines this tries to follow are those in - http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml - - 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 .cc, .cpp, .cu, .cuh and .h. Change the - extensions with the --extensions flag. - - Flags: - - output=vs7 - By default, the output is formatted to ease emacs parsing. Visual Studio - compatible output (vs7) may also be used. Other formats are unsupported. - - verbose=# - Specify a number 0-5 to restrict errors to certain verbosity levels. - - 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'. - - root=subdir - The root directory used for deriving header guard CPP variable. - By default, the header guard CPP variable is calculated as the relative - path to the directory that contains .git, .hg, or .svn. When this flag - is specified, the relative path is calculated from the specified - directory. If the specified directory does not exist, this flag is - ignored. - - Examples: - Assuing that src/.git exists, 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_ - - linelength=digits - This is the allowed line length for the project. The default value is - 80 characters. - - Examples: - --linelength=120 - - extensions=extension,extension,... - The allowed file extensions that cpplint will check - - Examples: - --extensions=hpp,cpp -""" - -# 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/deprecated', - 'build/endif_comment', - 'build/explicit_make_pair', - 'build/forward_decl', - 'build/header_guard', - 'build/include', - 'build/include_alpha', - 'build/include_order', - 'build/include_what_you_use', - '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/function', - 'readability/multiline_comment', - 'readability/multiline_string', - 'readability/namespace', - 'readability/nolint', - 'readability/nul', - 'readability/streams', - 'readability/todo', - 'readability/utf8', - 'runtime/arrays', - 'runtime/casting', - 'runtime/explicit', - 'runtime/int', - 'runtime/init', - 'runtime/invalid_increment', - 'runtime/member_string_references', - 'runtime/memset', - '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_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' - ] - -# The default state of the category filter. This is overrided 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/include_alpha'] - -# 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', - '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++ 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', - ]) - -# Assertion macros. These are defined in base/logging.h and -# testing/base/gunit.h. Note that the _M versions need to come first -# for substring matching to work. -_CHECK_MACROS = [ - 'DCHECK', 'CHECK', - 'EXPECT_TRUE_M', 'EXPECT_TRUE', - 'ASSERT_TRUE_M', 'ASSERT_TRUE', - 'EXPECT_FALSE_M', 'EXPECT_FALSE', - 'ASSERT_FALSE_M', 'ASSERT_FALSE', - ] - -# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE -_CHECK_REPLACEMENT = dict([(m, {}) for m 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 - _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement - _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % 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 - _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement - _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % 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 -_LIKELY_MY_HEADER = 3 -_POSSIBLE_MY_HEADER = 4 -_OTHER_HEADER = 5 - -# 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*[{(]') - - -_regexp_compile_cache = {} - -# Finds occurrences of NOLINT or NOLINT(...). -_RE_SUPPRESSION = re.compile(r'\bNOLINT\b(\([^)]*\))?') - -# {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 - -# The allowed line length of files. -# This is set by --linelength flag. -_line_length = 110 - -# The allowed extensions for file names -# This is set by --extensions flag. -_valid_extensions = set(['cc', 'h', 'cpp', 'cu', 'cuh']) - -def ParseNolintSuppressions(filename, raw_line, linenum, error): - """Updates the global list of 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. - """ - # FIXME(adonovan): "NOLINT(" is misparsed as NOLINT(*). - matched = _RE_SUPPRESSION.search(raw_line) - if matched: - category = matched.group(1) - if category in (None, '(*)'): # => "suppress all" - _error_suppressions.setdefault(None, set()).add(linenum) - else: - if category.startswith('(') and category.endswith(')'): - category = category[1:-1] - if category in _ERROR_CATEGORIES: - _error_suppressions.setdefault(category, set()).add(linenum) - else: - error(filename, linenum, 'readability/nolint', 5, - 'Unknown NOLINT error category: %s' % category) - - -def ResetNolintSuppressions(): - "Resets the set of NOLINT suppressions to empty." - _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/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. - """ - return (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) - - -class _IncludeState(dict): - """Tracks line numbers for includes, and the order in which includes appear. - - As a dict, an _IncludeState object serves as a mapping between include - filename and line number on which that file was included. - - 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_H_SECTION = 4 - - _TYPE_NAMES = { - _C_SYS_HEADER: 'C system header', - _CPP_SYS_HEADER: 'C++ 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_H_SECTION: 'other header', - } - - def __init__(self): - dict.__init__(self) - self.ResetSection() - - def ResetSection(self): - # The name of the current section. - self._section = self._INITIAL_SECTION - # The path of last found header. - self._last_header = '' - - 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 - not Match(r'^\s*$', 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 == _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[:] - self.counting = 'total' # In what way are we counting errors? - self.errors_by_category = {} # string to int dict storing error counts - - # output format: - # "emacs" - format that emacs can parse (default) - # "vs7" - format that Microsoft Visual Studio 7 can parse - self.output_format = 'emacs' - - def SetOutputFormat(self, output_format): - """Sets the output format for errors.""" - self.output_format = output_format - - 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[:] - 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 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 self.errors_by_category.iteritems(): - sys.stderr.write('Category \'%s\' errors found: %d\n' % - (category, count)) - sys.stderr.write('Total errors found: %d\n' % self.error_count) - -_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 _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) - - -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 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: - """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): - """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 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 = os.path.dirname(fullname) - while (root_dir != os.path.dirname(root_dir) and - not os.path.exists(os.path.join(root_dir, ".git")) and - not os.path.exists(os.path.join(root_dir, ".hg")) and - not os.path.exists(os.path.join(root_dir, ".svn"))): - root_dir = os.path.dirname(root_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.""" - 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 self.Extension()[1:] in ('c', 'cc', 'cpp', 'cxx') - - -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': - sys.stderr.write('%s(%s): %s [%s] [%d]\n' % ( - filename, linenum, message, category, confidence)) - elif _cpplint_state.output_format == 'eclipse': - sys.stderr.write('%s:%s: warning: %s [%s] [%d]\n' % ( - filename, linenum, message, category, confidence)) - else: - sys.stderr.write('%s:%s: %s [%s] [%d]\n' % ( - filename, linenum, message, category, confidence)) - - -# 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]+)') -# Matches strings. Escape codes should already be removed by ESCAPES. -_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"') -# Matches characters. Escape codes should already be removed by ESCAPES. -_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'") -# Matches multi-line C++ 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*/\*.*\*/\s*$| - /\*.*\*/\s+| - \s+/\*.*\*/(?=\W)| - /\*.*\*/)""", re.VERBOSE) - - -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 = '' - - else: - # Look for beginning of a raw string. - # See 2.14.15 [lex.string] for syntax. - matched = Match(r'^(.*)\b(?:R|u8R|uR|UR|LR)"([^\s\\()]*)\((.*)$', line) - if matched: - 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) + '""' - - 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 // dummy 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] = '// dummy' - - -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 3 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, and - 3) raw_lines member contains all the lines without processing. - All these three 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 not _RE_PATTERN_INCLUDE.match(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) - elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided) - elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided) - return elided - - -def FindEndOfExpressionInLine(line, startpos, depth, startchar, endchar): - """Find the position just after the matching endchar. - - Args: - line: a CleansedLines line. - startpos: start searching at this position. - depth: nesting level at startpos. - startchar: expression opening character. - endchar: expression closing character. - - Returns: - On finding matching endchar: (index just after matching endchar, 0) - Otherwise: (-1, new depth at end of this line) - """ - for i in xrange(startpos, len(line)): - if line[i] == startchar: - depth += 1 - elif line[i] == endchar: - depth -= 1 - if depth == 0: - return (i + 1, 0) - return (-1, depth) - - -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. - - 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] - startchar = line[pos] - if startchar not in '({[<': - return (line, clean_lines.NumLines(), -1) - if startchar == '(': endchar = ')' - if startchar == '[': endchar = ']' - if startchar == '{': endchar = '}' - if startchar == '<': endchar = '>' - - # Check first line - (end_pos, num_open) = FindEndOfExpressionInLine( - line, pos, 0, startchar, endchar) - if end_pos > -1: - return (line, linenum, end_pos) - - # Continue scanning forward - while linenum < clean_lines.NumLines() - 1: - linenum += 1 - line = clean_lines.elided[linenum] - (end_pos, num_open) = FindEndOfExpressionInLine( - line, 0, num_open, startchar, endchar) - if end_pos > -1: - return (line, linenum, end_pos) - - # Did not find endchar before end of file, give up - return (line, clean_lines.NumLines(), -1) - - -def FindStartOfExpressionInLine(line, endpos, depth, startchar, endchar): - """Find position at the matching startchar. - - 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. - depth: nesting level at endpos. - startchar: expression opening character. - endchar: expression closing character. - - Returns: - On finding matching startchar: (index at matching startchar, 0) - Otherwise: (-1, new depth at beginning of this line) - """ - for i in xrange(endpos, -1, -1): - if line[i] == endchar: - depth += 1 - elif line[i] == startchar: - depth -= 1 - if depth == 0: - return (i, 0) - return (-1, depth) - - -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] - endchar = line[pos] - if endchar not in ')}]>': - return (line, 0, -1) - if endchar == ')': startchar = '(' - if endchar == ']': startchar = '[' - if endchar == '}': startchar = '{' - if endchar == '>': startchar = '<' - - # Check last line - (start_pos, num_open) = FindStartOfExpressionInLine( - line, pos, 0, startchar, endchar) - if start_pos > -1: - return (line, linenum, start_pos) - - # Continue scanning backward - while linenum > 0: - linenum -= 1 - line = clean_lines.elided[linenum] - (start_pos, num_open) = FindStartOfExpressionInLine( - line, len(line) - 1, num_open, startchar, endchar) - if start_pos > -1: - return (line, linenum, start_pos) - - # Did not find startchar 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 - # dummy 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 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) - - fileinfo = FileInfo(filename) - file_path_from_root = fileinfo.RepositoryName() - if _root: - file_path_from_root = re.sub('^' + _root + os.sep, '', file_path_from_root) - return re.sub(r'[-./\s]', '_', file_path_from_root).upper() + '_' - - -def CheckForHeaderGuard(filename, 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. - lines: An array of strings, each representing a line of the file. - error: The function to call with any errors found. - """ - - cppvar = GetHeaderGuardCPPVariable(filename) - - ifndef = None - ifndef_linenum = 0 - define = None - endif = None - endif_linenum = 0 - for linenum, line in enumerate(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: - error(filename, 0, 'build/header_guard', 5, - 'No #ifndef header guard found, suggested CPP variable is: %s' % - cppvar) - return - - if not define: - error(filename, 0, 'build/header_guard', 5, - 'No #define 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, 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) - - if define != ifndef: - error(filename, 0, 'build/header_guard', 5, - '#ifndef and #define don\'t match, suggested CPP variable is: %s' % - cppvar) - return - - if endif != ('#endif // %s' % cppvar): - error_level = 0 - if endif != ('#endif // %s' % (cppvar + '_')): - error_level = 5 - - ParseNolintSuppressions(filename, lines[endif_linenum], endif_linenum, - error) - error(filename, endif_linenum, 'build/header_guard', error_level, - '#endif line should be "#endif // %s"' % cppvar) - - -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 u'\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.') - - -threading_list = ( - ('asctime(', 'asctime_r('), - ('ctime(', 'ctime_r('), - ('getgrgid(', 'getgrgid_r('), - ('getgrnam(', 'getgrnam_r('), - ('getlogin(', 'getlogin_r('), - ('getpwnam(', 'getpwnam_r('), - ('getpwuid(', 'getpwuid_r('), - ('gmtime(', 'gmtime_r('), - ('localtime(', 'localtime_r('), - ('rand(', 'rand_r('), - ('strtok(', 'strtok_r('), - ('ttyname(', 'ttyname_r('), - ) - - -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_function, multithread_safe_function in threading_list: - ix = line.find(single_thread_function) - # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison - if ix >= 0 and (ix == 0 or (not line[ix - 1].isalnum() and - line[ix - 1] not in ('_', '.', '>'))): - error(filename, linenum, 'runtime/threadsafe_fn', 2, - 'Consider using ' + multithread_safe_function + - '...) instead of ' + single_thread_function + - '...) 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*).') - - -class _BlockInfo(object): - """Stores information about a generic block of code.""" - - def __init__(self, seen_open_brace): - self.seen_open_brace = seen_open_brace - self.open_parentheses = 0 - self.inline_asm = _NO_ASM - - 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 - - -class _ClassInfo(_BlockInfo): - """Stores information about a class.""" - - def __init__(self, name, class_or_struct, clean_lines, linenum): - _BlockInfo.__init__(self, False) - self.name = name - self.starting_linenum = linenum - self.is_derived = False - 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. - initial_indent = Match(r'^( *)\S', clean_lines.raw_lines[linenum]) - if initial_indent: - self.class_indent = len(initial_indent.group(1)) - else: - self.class_indent = 0 - - # 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): - # 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, False) - self.name = name or '' - self.starting_linenum = linenum - - 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*(//|/\*).*\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*(//|/\*).*\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*(//|/\*).*\bnamespace[\*/\.\\\s]*$', line): - error(filename, linenum, 'readability/namespace', 5, - '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 = [] - - # 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 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 - - 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] - - # Update pp_stack first - 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 { - # }; - # - # Templates with class arguments may confuse the parser, for example: - # template , - # class Vector = vector > - # class HeapQueue { - # - # Because this parser has no nesting state about templates, by the - # time it saw "class Comparator", it may think that it's a new class. - # Nested templates have a similar problem: - # template < - # typename ExportedType, - # typename TupleType, - # template class ImplTemplate> - # - # To avoid these cases, we ignore classes that are followed by '=' or '>' - class_decl_match = Match( - r'\s*(template\s*<[\w\s<>,:]*>\s*)?' - r'(class|struct)\s+([A-Z_]+\s+)*(\w+(?:::\w+)*)' - r'(([^=>]|<[^<>]*>|<[^<>]*<[^<>]*>\s*>)*)$', line) - if (class_decl_match and - (not self.stack or self.stack[-1].open_parentheses == 0)): - self.stack.append(_ClassInfo( - class_decl_match.group(4), class_decl_match.group(2), - clean_lines, linenum)) - line = class_decl_match.group(5) - - # 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 - else: - self.stack.append(_BlockInfo(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. - args = Match(r'\s+(?:inline\s+)?%s\s*\(([^,()]+)\)' - % re.escape(base_classname), - line) - if (args and - args.group(1) != 'void' and - not Match(r'(const\s+)?%s(\s+const)?\s*(?:<\w+>\s*)?&' - % re.escape(base_classname), args.group(1).strip())): - error(filename, linenum, 'runtime/explicit', 5, - 'Single-argument constructors should be marked explicit.') - - -def CheckSpacingForFunctionCall(filename, line, linenum, error): - """Checks for the correctness of various spacing around function calls. - - Args: - filename: The name of the current file. - line: The text of the line to check. - linenum: The number of the line to check. - error: The function to call with any errors found. - """ - - # 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'#\s*define|typedef', fncall) and - not Search(r'\w\s+\((\w+::)*\*\w+\)\(', fncall)): - 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 CheckForFunctionLengths(filename, clean_lines, linenum, - function_state, error): - """Reports for long function bodies. - - For an overview why this is done, see: - http://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] - raw = clean_lines.raw_lines - raw_line = raw[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 - elif 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(comment, filename, linenum, error): - """Checks for common mistakes in TODO comments. - - Args: - comment: The text of the comment from the line in question. - filename: The name of the current file. - linenum: The number of the line to check. - error: The function to call with any errors found. - """ - 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') - -def CheckAccess(filename, clean_lines, linenum, nesting_state, error): - """Checks for improper use of DISALLOW* 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. - 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] # get rid of comments and strings - - matched = Match((r'\s*(DISALLOW_COPY_AND_ASSIGN|' - r'DISALLOW_EVIL_CONSTRUCTORS|' - r'DISALLOW_IMPLICIT_CONSTRUCTORS)'), line) - if not matched: - return - if nesting_state.stack and isinstance(nesting_state.stack[-1], _ClassInfo): - if nesting_state.stack[-1].access != 'private': - error(filename, linenum, 'readability/constructors', 3, - '%s must be in the private: section' % matched.group(1)) - - else: - # Found DISALLOW* macro outside a class declaration, or perhaps it - # was used inside a function when it should have been part of the - # class declaration. We could issue a warning here, but it - # probably resulted in a compiler error already. - pass - - -def FindNextMatchingAngleBracket(clean_lines, linenum, init_suffix): - """Find the corresponding > to close a template. - - Args: - clean_lines: A CleansedLines instance containing the file. - linenum: Current line number. - init_suffix: Remainder of the current line after the initial <. - - Returns: - True if a matching bracket exists. - """ - line = init_suffix - nesting_stack = ['<'] - while True: - # Find the next operator that can tell us whether < is used as an - # opening bracket or as a less-than operator. We only want to - # warn on the latter case. - # - # We could also check all other operators and terminate the search - # early, e.g. if we got something like this "a(),;\[\]]*([<>(),;\[\]])(.*)$', line) - if match: - # Found an operator, update nesting stack - operator = match.group(1) - line = match.group(2) - - if nesting_stack[-1] == '<': - # Expecting closing angle bracket - if operator in ('<', '(', '['): - nesting_stack.append(operator) - elif operator == '>': - nesting_stack.pop() - if not nesting_stack: - # Found matching angle bracket - return True - elif operator == ',': - # Got a comma after a bracket, this is most likely a template - # argument. We have not seen a closing angle bracket yet, but - # it's probably a few lines later if we look for it, so just - # return early here. - return True - else: - # Got some other operator. - return False - - else: - # Expecting closing parenthesis or closing bracket - if operator in ('<', '(', '['): - nesting_stack.append(operator) - elif operator in (')', ']'): - # We don't bother checking for matching () or []. If we got - # something like (] or [), it would have been a syntax error. - nesting_stack.pop() - - else: - # Scan the next line - linenum += 1 - if linenum >= len(clean_lines.elided): - break - line = clean_lines.elided[linenum] - - # Exhausted all remaining lines and still no matching angle bracket. - # Most likely the input was incomplete, otherwise we should have - # seen a semicolon and returned early. - return True - - -def FindPreviousMatchingAngleBracket(clean_lines, linenum, init_prefix): - """Find the corresponding < that started a template. - - Args: - clean_lines: A CleansedLines instance containing the file. - linenum: Current line number. - init_prefix: Part of the current line before the initial >. - - Returns: - True if a matching bracket exists. - """ - line = init_prefix - nesting_stack = ['>'] - while True: - # Find the previous operator - match = Search(r'^(.*)([<>(),;\[\]])[^<>(),;\[\]]*$', line) - if match: - # Found an operator, update nesting stack - operator = match.group(2) - line = match.group(1) - - if nesting_stack[-1] == '>': - # Expecting opening angle bracket - if operator in ('>', ')', ']'): - nesting_stack.append(operator) - elif operator == '<': - nesting_stack.pop() - if not nesting_stack: - # Found matching angle bracket - return True - elif operator == ',': - # Got a comma before a bracket, this is most likely a - # template argument. The opening angle bracket is probably - # there if we look for it, so just return early here. - return True - else: - # Got some other operator. - return False - - else: - # Expecting opening parenthesis or opening bracket - if operator in ('>', ')', ']'): - nesting_stack.append(operator) - elif operator in ('(', '['): - nesting_stack.pop() - - else: - # Scan the previous line - linenum -= 1 - if linenum < 0: - break - line = clean_lines.elided[linenum] - - # Exhausted all earlier lines and still no matching angle bracket. - return False - - -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. - if IsBlankLine(line) and not nesting_state.InNamespaceBody(): - 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, we complain if there's a comment too near the text - commentpos = line.find('//') - if commentpos != -1: - # Check if the // may be in quotes. If so, ignore it - # Comparisons made explicit for clarity -- pylint: disable=g-explicit-bool-comparison - if (line.count('"', 0, commentpos) - - line.count('\\"', 0, commentpos)) % 2 == 0: # not in quotes - # Allow one space for new scopes, two spaces otherwise: - if (not Match(r'^\s*{ //', line) 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') - # There should always be a space between the // and the comment - commentend = commentpos + 2 - if commentend < len(line) and not line[commentend] == ' ': - # but some lines are exceptions -- e.g. if they're big - # comment delimiters like: - # //---------------------------------------------------------- - # or are an empty C++ style Doxygen comment, like: - # /// - # or C++ style Doxygen comments placed after the variable: - # ///< Header comment - # //!< Header comment - # or they begin with multiple slashes followed by a space: - # //////// Header comment - match = (Search(r'[=/-]{4,}\s*$', line[commentend:]) or - Search(r'^/$', line[commentend:]) or - Search(r'^!< ', line[commentend:]) or - Search(r'^/< ', line[commentend:]) or - Search(r'^/+ ', line[commentend:])) - if not match: - error(filename, linenum, 'whitespace/comments', 4, - 'Should have a space between // and comment') - CheckComment(line[commentpos:], filename, linenum, error) - - line = clean_lines.elided[linenum] # get rid of comments and strings - - # Don't try to do spacing checks for operator methods - line = re.sub(r'operator(==|!=|<|<<|<=|>=|>>|>)\(', 'operator\(', line) - - # 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.]=[\w.]', line) and not Search(r'\b(if|while) ', 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 >. - match = Search(r'[^<>=!\s](==|!=|<=|>=)[^<>=!\s]', line) - if match: - error(filename, linenum, 'whitespace/operators', 3, - 'Missing spaces around %s' % match.group(1)) - # We allow no-spaces around << when used like this: 10<<20, but - # not otherwise (particularly, not when used as streams) - # Also ignore using ns::operator<<; - match = Search(r'(operator|\S)(?:L|UL|ULL|l|ul|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 <<') - elif not Match(r'#.*include', line): - # Avoid false positives on -> - reduced_line = line.replace('->', '') - - # 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 = Search(r'[^\s<]<([^\s=<].*)', reduced_line) - if (match and - not FindNextMatchingAngleBracket(clean_lines, linenum, match.group(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 = Search(r'^(.*[^\s>])>[^\s=>]', reduced_line) - if (match and - not FindPreviousMatchingAngleBracket(clean_lines, linenum, - match.group(1))): - 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)) - - # A pet peeve of mine: 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)) - - # 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]', 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 ;') - - # Next we will look for issues with function calls. - CheckSpacingForFunctionCall(filename, line, linenum, error) - - # 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. And since you should never have braces at the beginning of a line, - # this is an easy test. - 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[{...}] = ...; - # - # 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. - (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] - if not Match(r'^[\s}]*[{.;,)<\]]', trailing_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 spaces before your brackets, except maybe after - # 'delete []' or 'new char * []'. - if Search(r'\w\s+\[', line) and not Search(r'delete\s+\[', line): - error(filename, linenum, 'whitespace/braces', 5, - 'Extra space before [') - - # 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.') - - # In range-based for, we wanted spaces before and after the colon, but - # not around "::" tokens that might appear. - if (Search('for *\(.*[^:]:[^: ]', line) or - Search('for *\(.*[^: ]:[^:]', line)): - error(filename, linenum, 'whitespace/forcolon', 2, - 'Missing space around colon in range-based for loop') - - -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. - prevline = GetPreviousNonBlankLine(clean_lines, linenum)[0] - if (not Search(r'[,;:}{(]\s*$', prevline) and - not Match(r'\s*#', 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\s*', 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'}\s*else[^{]*$', line) or Match(r'[^}]*else\s*{', line): - if Search(r'}\s*else if([^{]*)$', line): # could be multi-line if - # find the ( after the if - pos = line.find('else if') - pos = line.find('(', pos) - if pos > 0: - (endline, _, endpos) = CloseExpression(clean_lines, linenum, pos) - if endline[endpos:].find('{') == -1: # 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') - else: # common case: else not followed by a multi-line if - 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') - - # 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 use a whitelist approach to check these - # rather than a blacklist. 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 whitelist of safe macros instead of a blacklist 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 whitelist wrong means some extra - # semicolons, while the downside for getting the blacklist wrong - # would result in compile errors. - # - # In addition to macros, we also don't want to warn on compound - # literals. - 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_]+)\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 - Search(r'\s+=\s*$', line_prefix)): - 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. - 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') - - -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 = None - start_pos = -1 - for macro in _CHECK_MACROS: - i = lines[linenum].find(macro) - if i >= 0: - check_macro = macro - - # 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' + check_macro + r'\s*)\(', lines[linenum]) - if not matched: - continue - start_pos = len(matched.group(1)) - break - if not check_macro or start_pos < 0: - # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT' - 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 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, 1, '(', ')') - 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): - 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] - - 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; - initial_spaces = 0 - cleansed_line = clean_lines.elided[linenum] - while initial_spaces < len(line) and line[initial_spaces] == ' ': - initial_spaces += 1 - if line and line[-1].isspace(): - error(filename, linenum, 'whitespace/end_of_line', 4, - 'Line ends in whitespace. Consider deleting these extra spaces.') - # There are certain situations we allow one space, notably for section labels - elif ((initial_spaces == 1 or initial_spaces == 3) and - not Match(r'\s*\w+\s*:\s*$', cleansed_line)): - error(filename, linenum, 'whitespace/indent', 3, - 'Weird number of spaces at line-start. ' - 'Are you using a 2-space indent?') - - # Check if the line is a header guard. - is_header_guard = False - if file_extension == 'h': - 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. - if (not line.startswith('#include') and not is_header_guard and - not Match(r'^\s*//.*http(s?)://\S*$', line) and - not Match(r'^// \$Id:.*#[0-9]+ \$$', line)): - line_width = GetLineWidth(line) - extended_length = int((_line_length * 1.25)) - if line_width > extended_length: - error(filename, linenum, 'whitespace/line_length', 4, - 'Lines should very rarely be longer than %i characters' % - extended_length) - elif 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 - # 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) - CheckEmptyBlockBody(filename, clean_lines, linenum, error) - CheckAccess(filename, clean_lines, linenum, nesting_state, error) - CheckSpacing(filename, clean_lines, linenum, nesting_state, 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_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"') -_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 ('test.cc', 'regtest.cc', 'unittest.cc', - 'inl.h', 'impl.h', 'internal.h'): - 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 _IsTestFilename(filename): - """Determines if the given filename has a suffix that identifies it as a test. - - Args: - filename: The input filename. - - Returns: - True if 'filename' looks like a test, False otherwise. - """ - if (filename.endswith('_test.cc') or - filename.endswith('_unittest.cc') or - filename.endswith('_regtest.cc')): - return True - else: - return False - - -def _ClassifyInclude(fileinfo, include, is_system): - """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. - is_system: True if the #include used <> rather than "". - - 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', 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_h = include in _CPP_HEADERS - - if is_system: - if is_cpp_h: - return _CPP_SYS_HEADER - else: - return _C_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)) - if target_base == include_base and ( - include_dir == target_dir or - include_dir == os.path.normpath(target_dir + '/../public')): - 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" - if _RE_PATTERN_INCLUDE_NEW_STYLE.search(line): - error(filename, linenum, 'build/include', 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) - is_system = (match.group(1) == '<') - if include in include_state: - error(filename, linenum, 'build/include', 4, - '"%s" already included at %s:%s' % - (include, filename, include_state[include])) - else: - include_state[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, is_system)) - 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) - - # Look for any of the stream classes that are part of standard C++. - match = _RE_PATTERN_INCLUDE.match(line) - if match: - include = match.group(2) - if Match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include): - # Many unit tests use cout, so we exempt them. - if not _IsTestFilename(filename): - error(filename, linenum, 'readability/streams', 3, - 'Streams are highly discouraged.') - - -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(sugawarayu): 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(matching_punctuation.itervalues()) - - # 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')') - - -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. - if Match(r'^\s*#\s*(?:ifdef|elif|else|endif)\b', line): - include_state.ResetSection() - - # Make Windows paths like Unix. - fullname = os.path.abspath(filename).replace('\\', '/') - - # TODO(unknown): figure out if they're using default arguments in fn proto. - - # 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+)?\b' # Grab 'new' operator, if it's there - r'(int|float|double|bool|char|int32|uint32|int64|uint64)' - r'(\([^)].*)', line) - if match: - matched_new = match.group(1) - matched_type = match.group(2) - matched_funcptr = match.group(3) - - # gMock methods are defined using some variant of MOCK_METHODx(name, type) - # where type may be float(), int(string), etc. Without context they are - # virtually indistinguishable from int(x) casts. Likewise, gMock's - # MockCallback takes a template parameter of the form return_type(arg_type), - # which looks much like the cast we're trying to detect. - # - # std::function<> wrapper has a similar problem. - # - # Return types for function pointers also look like casts if they - # don't have an extra space. - if (matched_new is None and # If new operator, then this isn't a cast - not (Match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line) or - Search(r'\bMockCallback<.*>', line) or - Search(r'\bstd::function<.*>', line)) and - not (matched_funcptr and - Match(r'\((?:[^() ]+::\s*\*\s*)?[^() ]+\)\s*\(', - matched_funcptr))): - # Try a bit harder to catch gmock lines: the only place where - # something looks like an old-style cast is where we declare the - # return type of the mocked method, and the only time when we - # are missing context is if MOCK_METHOD was split across - # multiple lines. The missing MOCK_METHOD is usually one or two - # lines back, so scan back one or two lines. - # - # It's not possible for gmock macros to appear in the first 2 - # lines, since the class head + section name takes up 2 lines. - if (linenum < 2 or - not (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]))): - error(filename, linenum, 'readability/casting', 4, - 'Using deprecated casting style. ' - 'Use static_cast<%s>(...) instead' % - matched_type) - - CheckCStyleCast(filename, linenum, line, clean_lines.raw_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, linenum, line, clean_lines.raw_lines[linenum], - 'const_cast', r'\((char\s?\*+\s?)\)\s*"', error): - pass - else: - # Check pointer casts for other than string constants - CheckCStyleCast(filename, linenum, line, clean_lines.raw_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. - match = Search( - r'(?:&\(([^)]+)\)[\w(])|' - r'(?:&(static|dynamic|down|reinterpret)_cast\b)', line) - if match and match.group(1) != '*': - 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')) - - # Create an extended_line, which is the concatenation of the current and - # next lines, for more effective checking of code that may span more than one - # line. - if linenum + 1 < clean_lines.NumLines(): - extended_line = line + clean_lines.elided[linenum + 1] - else: - extended_line = line - - # 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. - match = Match( - r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)', - line) - # Make sure it's not a function. - # Function template specialization looks like: "string foo(...". - # Class template definitions look like: "string Foo::Method(...". - # - # Also ignore things that look like operators. These are matched separately - # because operator names cross non-word boundaries. If we change the pattern - # above, we would decrease the accuracy of matching identifiers. - if (match and - not Search(r'\boperator\W', line) and - not Match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)', match.group(3))): - error(filename, linenum, 'runtime/string', 4, - 'For a static/global string constant, use a C style string instead: ' - '"%schar %s[]".' % - (match.group(1), match.group(2))) - - if Search(r'\b([A-Za-z0-9_]*_)\(\1\)', line): - error(filename, linenum, 'runtime/init', 4, - 'You seem to be initializing a member variable with itself.') - - if file_extension == 'h': - # 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 have DISALLOW_EVIL_CONSTRUCTORS - # (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)) - - # 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\b', line): - error(filename, linenum, 'runtime/printf', 5, - 'Never use sprintf. Use snprintf instead.') - match = Search(r'\b(strcpy|strcat)\b', line) - if match: - error(filename, linenum, 'runtime/printf', 4, - 'Almost always, snprintf is better than %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(sugawarayu): 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): - 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.") - - # If DISALLOW_EVIL_CONSTRUCTORS, DISALLOW_COPY_AND_ASSIGN, or - # DISALLOW_IMPLICIT_CONSTRUCTORS is present, then it should be the last thing - # in the class declaration. - match = Match( - (r'\s*' - r'(DISALLOW_(EVIL_CONSTRUCTORS|COPY_AND_ASSIGN|IMPLICIT_CONSTRUCTORS))' - r'\(.*\);$'), - line) - if match and linenum + 1 < clean_lines.NumLines(): - next_line = clean_lines.elided[linenum + 1] - # We allow some, but not all, declarations of variables to be present - # in the statement that defines the class. The [\w\*,\s]* fragment of - # the regular expression below allows users to declare instances of - # the class or pointers to instances, but not less common types such - # as function pointers or arrays. It's a tradeoff between allowing - # reasonable code and avoiding trying to parse more C++ using regexps. - if not Search(r'^\s*}[\w\*,\s]*;', next_line): - error(filename, linenum, 'readability/constructors', 3, - match.group(1) + ' should be the last thing in the class') - - # 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 (file_extension == 'h' - and Search(r'\bnamespace\s*{', line) - and line[-1] != '\\'): - error(filename, linenum, 'build/namespaces', 4, - 'Do not use unnamed namespaces in header files. See ' - 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces' - ' for more information.') - -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 - - # 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(unknwon): Doesn't account for preprocessor directives. - # # TODO(unknown): Doesn't account for 'catch(Exception& e)' [rare]. - # check_params = False - # if not nesting_state.stack: - # check_params = True # top level - # elif (isinstance(nesting_state.stack[-1], _ClassInfo) or - # isinstance(nesting_state.stack[-1], _NamespaceInfo)): - # check_params = True # within class or namespace - # elif Match(r'.*{\s*$', line): - # if (len(nesting_state.stack) == 1 or - # isinstance(nesting_state.stack[-2], _ClassInfo) or - # isinstance(nesting_state.stack[-2], _NamespaceInfo)): - # check_params = True # just opened global/class/namespace block - # # 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. - # whitelisted_functions = (r'(?:[sS]wap(?:<\w:+>)?|' - # r'operator\s*[<>][<>]|' - # r'static_assert|COMPILE_ASSERT' - # r')\s*\(') - # if Search(whitelisted_functions, line): - # check_params = False - # elif not Search(r'\S+\([^)]*$', line): - # # Don't see a whitelisted 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(whitelisted_functions, clean_lines.elided[linenum - i - 1])): - # check_params = False - # break - - # if check_params: - # 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): - # error(filename, linenum, 'runtime/references', 2, - # 'Is this a non-const reference? ' - # 'If so, make const or use a pointer: ' + - # ReplaceAll(' *<', '<', parameter)) - - -def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern, - error): - """Checks for a C-style cast by looking for the pattern. - - Args: - filename: The name of the current file. - linenum: The number of the line to check. - line: The line of code to check. - raw_line: The raw line of code to check, with comments. - 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. - """ - match = Search(pattern, line) - if not match: - return False - - # Exclude lines with sizeof, since sizeof looks like a cast. - sizeof_match = Match(r'.*sizeof\s*$', line[0:match.start(1) - 1]) - if sizeof_match: - return False - - # operator++(int) and operator--(int) - if (line[0:match.start(1) - 1].endswith(' operator++') or - line[0:match.start(1) - 1].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, instead issue warnings for unnamed arguments where - # appropriate. - # - # These are things that we want warnings for, since the style guide - # explicitly require all parameters to be named: - # Function(int); - # Function(int) { - # ConstMember(int) const; - # ConstMember(int) const { - # ExceptionMember(int) throw (...); - # ExceptionMember(int) throw (...) { - # PureVirtual(int) = 0; - # - # These are functions of some sort, where the compiler would be fine - # if they had named parameters, but people often omit those - # identifiers to reduce clutter: - # (FunctionPointer)(int); - # (FunctionPointer)(int) = value; - # Function((function_pointer_arg)(int)) - # ; - # <(FunctionPointerTemplateArgument)(int)>; - remainder = line[match.end(0):] - if Match(r'^\s*(?:;|const\b|throw\b|=|>|\{|\))', remainder): - # Looks like an unnamed parameter. - - # Don't warn on any kind of template arguments. - if Match(r'^\s*>', remainder): - return False - - # Don't warn on assignments to function pointers, but keep warnings for - # unnamed parameters to pure virtual functions. Note that this pattern - # will also pass on assignments of "0" to function pointers, but the - # preferred values for those would be "nullptr" or "NULL". - matched_zero = Match(r'^\s=\s*(\S+)\s*;', remainder) - if matched_zero and matched_zero.group(1) != '0': - return False - - # Don't warn on function pointer declarations. For this we need - # to check what came before the "(type)" string. - if Match(r'.*\)\s*$', line[0:match.start(0)]): - return False - - # Don't warn if the parameter is named with block comments, e.g.: - # Function(int /*unused_param*/); - if '/*' in raw_line: - return False - - # Passed all filters, issue warning here. - error(filename, linenum, 'readability/function', 3, - 'All parameters should be named in a function') - return True - - # 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 - - -_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',)), - ('', ('map', 'multimap',)), - ('', ('allocator',)), - ('', ('queue', 'priority_queue',)), - ('', ('set', 'multiset',)), - ('', ('stack',)), - ('', ('char_traits', 'basic_string',)), - ('', ('pair',)), - ('', ('vector',)), - - # gcc extensions. - # Note: std::hash is their hash, ::hash is our hash - ('', ('hash_map', 'hash_multimap',)), - ('', ('hash_set', 'hash_multiset',)), - ('', ('slist',)), - ) - -_RE_PATTERN_STRING = re.compile(r'\bstring\b') - -_re_pattern_algorithm_header = [] -for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap', - 'transform'): - # Match max(..., ...), max(..., ...), but not foo->max, foo.max or - # type::max(). - _re_pattern_algorithm_header.append( - (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'), - _template, - '')) - -_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 .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. - """ - - if not filename_cc.endswith('.cc'): - return (False, '') - filename_cc = filename_cc[:-len('.cc')] - if filename_cc.endswith('_unittest'): - filename_cc = filename_cc[:-len('_unittest')] - elif filename_cc.endswith('_test'): - filename_cc = filename_cc[:-len('_test')] - filename_cc = filename_cc.replace('/public/', '/') - filename_cc = filename_cc.replace('/internal/', '/') - - if not filename_h.endswith('.h'): - return (False, '') - filename_h = filename_h[:-len('.h')] - 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_state, io=codecs): - """Fill up the include_state with new includes found from the file. - - Args: - filename: the name of the header to read. - include_state: an _IncludeState instance 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 succesfully added. False otherwise. - """ - headerfile = None - try: - headerfile = io.open(filename, 'r', 'utf8', 'replace') - except IOError: - return False - 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) - # The value formatting is cute, but not really used right now. - # What matters here is that the key is in include_state. - include_state.setdefault(include, '%s:%d' % (filename, linenum)) - return True - - -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_algorithm_header: - 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: - if pattern.search(line): - 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 copy the include_state so it is only messed up within this function. - include_state = include_state.copy() - - # Did we find the header for this file (if any) and succesfully 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_state is modified during iteration, so we iterate over a copy of - # the keys. - header_keys = include_state.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_state, 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 filename.endswith('.cc') and not header_found: - return - - # All the lines have been processed, report the errors found. - for required_header_unstripped in required: - template = required[required_header_unstripped][1] - if required_header_unstripped.strip('<>"') not in include_state: - 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++0x 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 ProcessLine(filename, file_extension, clean_lines, line, - include_state, function_state, nesting_state, error, - extra_check_functions=[]): - """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) - if nesting_state.stack and nesting_state.stack[-1].inline_asm != _NO_ASM: - 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) - for check_fn in extra_check_functions: - check_fn(filename, clean_lines, line, error) - -def ProcessFileData(filename, file_extension, lines, error, - extra_check_functions=[]): - """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) - - if file_extension == 'h': - CheckForHeaderGuard(filename, lines, error) - - RemoveMultiLineComments(filename, lines, error) - clean_lines = CleansedLines(lines) - for line in xrange(clean_lines.NumLines()): - ProcessLine(filename, file_extension, clean_lines, line, - include_state, function_state, nesting_state, error, - extra_check_functions) - nesting_state.CheckCompletedBlocks(filename, error) - - CheckForIncludeWhatYouUse(filename, clean_lines, 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 ProcessFile(filename, vlevel, extra_check_functions=[]): - """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) - - 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 it is not expected to be present (i.e. os.linesep != - # '\r\n' as in Windows), a warning is issued below if this file - # is processed. - - if filename == '-': - lines = codecs.StreamReaderWriter(sys.stdin, - codecs.getreader('utf8'), - codecs.getwriter('utf8'), - 'replace').read().split('\n') - else: - lines = codecs.open(filename, 'r', 'utf8', 'replace').read().split('\n') - - carriage_return_found = False - # Remove trailing '\r'. - for linenum in range(len(lines)): - if lines[linenum].endswith('\r'): - lines[linenum] = lines[linenum].rstrip('\r') - carriage_return_found = True - - except IOError: - sys.stderr.write( - "Skipping input '%s': Can't open for reading\n" % filename) - 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 _valid_extensions: - sys.stderr.write('Ignoring %s; not a valid file name ' - '(%s)\n' % (filename, ', '.join(_valid_extensions))) - else: - ProcessFileData(filename, file_extension, lines, Error, - extra_check_functions) - if carriage_return_found and os.linesep != '\r\n': - # Use 0 for linenum since outputting only one error for potentially - # several lines. - Error(filename, 0, 'whitespace/newline', 1, - 'One or more unexpected \\r (^M) found;' - 'better to use only a \\n') - - sys.stderr.write('Done processing %s\n' % filename) - - -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) - if message: - sys.exit('\nFATAL ERROR: ' + message) - else: - sys.exit(1) - - -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=', - 'counting=', - 'filter=', - 'root=', - 'linelength=', - 'extensions=']) - except getopt.GetoptError: - PrintUsage('Invalid arguments.') - - verbosity = _VerboseLevel() - output_format = _OutputFormat() - filters = '' - counting_style = '' - - for (opt, val) in opts: - if opt == '--help': - PrintUsage(None) - elif opt == '--output': - if val not in ('emacs', 'vs7', 'eclipse'): - PrintUsage('The only allowed output formats are emacs, vs7 and eclipse.') - output_format = val - elif opt == '--verbose': - 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 == '--linelength': - global _line_length - try: - _line_length = int(val) - except ValueError: - PrintUsage('Line length must be digits.') - elif opt == '--extensions': - global _valid_extensions - try: - _valid_extensions = set(val.split(',')) - except ValueError: - PrintUsage('Extensions must be comma seperated list.') - - if not filenames: - PrintUsage('No files were specified.') - - _SetOutputFormat(output_format) - _SetVerboseLevel(verbosity) - _SetFilters(filters) - _SetCountingStyle(counting_style) - - return filenames - - -def main(): - filenames = ParseArguments(sys.argv[1:]) - - # 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.StreamReaderWriter(sys.stderr, - codecs.getreader('utf8'), - codecs.getwriter('utf8'), - 'replace') - - _cpplint_state.ResetErrorCounts() - for filename in filenames: - ProcessFile(filename, _cpplint_state.verbose_level) - _cpplint_state.PrintErrorCounts() - - sys.exit(_cpplint_state.error_count > 0) - - -if __name__ == '__main__': - main() diff --git a/codestyle/uncrustify.cfg b/codestyle/uncrustify.cfg deleted file mode 100644 index 9f438c4ab..000000000 --- a/codestyle/uncrustify.cfg +++ /dev/null @@ -1,1607 +0,0 @@ -# Uncrustify 0.63 - -# -# General options -# - -# The type of line endings -newlines = auto # auto/lf/crlf/cr - -# The original size of tabs in the input -input_tab_size = 4 # number - -# The size of tabs in the output (only used if align_with_tabs=true) -output_tab_size = 4 # number - -# The ASCII value of the string escape char, usually 92 (\) or 94 (^). (Pawn) -string_escape_char = 92 # number - -# Alternate string escape char for Pawn. Only works right before the quote char. -string_escape_char2 = 0 # number - -# Allow interpreting '>=' and '>>=' as part of a template in 'void f(list>=val);'. -# If true (default), 'assert(x<0 && y>=3)' will be broken. -# Improvements to template detection may make this option obsolete. -tok_split_gte = true # false/true - -# Control what to do with the UTF-8 BOM (recommend 'remove') -utf8_bom = ignore # ignore/add/remove/force - -# If the file contains bytes with values between 128 and 255, but is not UTF-8, then output as UTF-8 -utf8_byte = false # false/true - -# Force the output encoding to UTF-8 -utf8_force = false # false/true - -# -# Indenting -# - -# The number of columns to indent per level. -# Usually 2, 3, 4, or 8. -indent_columns = 2 # number - -# The continuation indent. If non-zero, this overrides the indent of '(' and '=' continuation indents. -# For FreeBSD, this is set to 4. -indent_continue = 0 # number - -# How to use tabs when indenting code -# 0=spaces only -# 1=indent with tabs to brace level, align with spaces -# 2=indent and align with tabs, using spaces when not on a tabstop -indent_with_tabs = 0 # number - -# Comments that are not a brace level are indented with tabs on a tabstop. -# Requires indent_with_tabs=2. If false, will use spaces. -indent_cmt_with_tabs = false # false/true - -# Whether to indent strings broken by '\' so that they line up -indent_align_string = true # false/true - -# The number of spaces to indent multi-line XML strings. -# Requires indent_align_string=True -indent_xml_string = 0 # number - -# Spaces to indent '{' from level -indent_brace = 0 # number - -# Indent continued shift expressions ('<<' and '>>') instead of aligning. -# Turn align_left_shift off when enabling this. -indent_shift = false # false/true - -# Whether braces are indented to the body level -indent_braces = false # false/true - -# Disabled indenting function braces if indent_braces is true -indent_braces_no_func = false # false/true - -# Disabled indenting class braces if indent_braces is true -indent_braces_no_class = false # false/true - -# Disabled indenting struct braces if indent_braces is true -indent_braces_no_struct = false # false/true - -# Indent based on the size of the brace parent, i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. -indent_brace_parent = false # false/true - -# Whether the 'namespace' body is indented -indent_namespace = false # false/true - -# The number of spaces to indent a namespace block -indent_namespace_level = 0 # number - -# If the body of the namespace is longer than this number, it won't be indented. -# Requires indent_namespace=true. Default=0 (no limit) -indent_namespace_limit = 0 # number - -# Whether the 'extern "C"' body is indented -indent_extern = false # false/true - -# Whether the 'class' body is indented -indent_class = true # false/true - -# Whether to indent the stuff after a leading class colon -indent_class_colon = true # false/true -indent_constr_colon = true # false/true - -# Virtual indent from the ':' for member initializers. Default is 2 -indent_ctor_init_leading = 2 # number - -# Additional indenting for constructor initializer list -indent_ctor_init = 0 # number - -# False=treat 'else\nif' as 'else if' for indenting purposes -# True=indent the 'if' one level -indent_else_if = false # false/true - -# Amount to indent variable declarations after a open brace. neg=relative, pos=absolute -indent_var_def_blk = 0 # number - -# Indent continued variable declarations instead of aligning. -indent_var_def_cont = true # false/true - -# True: force indentation of function definition to start in column 1 -# False: use the default behavior -indent_func_def_force_col1 = false # false/true - -# True: indent continued function call parameters one indent level -# False: align parameters under the open paren -indent_func_call_param = false # false/true - -# Same as indent_func_call_param, but for function defs -indent_func_def_param = false # false/true - -# Same as indent_func_call_param, but for function protos -indent_func_proto_param = false # false/true - -# Same as indent_func_call_param, but for class declarations -indent_func_class_param = false # false/true - -# Same as indent_func_call_param, but for class variable constructors -indent_func_ctor_var_param = false # false/true - -# Same as indent_func_call_param, but for templates -indent_template_param = false # false/true - -# Double the indent for indent_func_xxx_param options -indent_func_param_double = false # false/true - -# Indentation column for standalone 'const' function decl/proto qualifier -indent_func_const = 0 # number - -# Indentation column for standalone 'throw' function decl/proto qualifier -indent_func_throw = 0 # number - -# The number of spaces to indent a continued '->' or '.' -# Usually set to 0, 1, or indent_columns. -indent_member = 0 # number - -# Spaces to indent single line ('//') comments on lines before code -indent_sing_line_comments = 0 # number - -# If set, will indent trailing single line ('//') comments relative -# to the code instead of trying to keep the same absolute column -indent_relative_single_line_comments = false # false/true - -# Spaces to indent 'case' from 'switch' -# Usually 0 or indent_columns. -indent_switch_case = 2 # number - -# Spaces to shift the 'case' line, without affecting any other lines -# Usually 0. -indent_case_shift = 0 # number - -# Spaces to indent '{' from 'case'. -# By default, the brace will appear under the 'c' in case. -# Usually set to 0 or indent_columns. -indent_case_brace = 2 # number - -# Whether to indent comments found in first column -indent_col1_comment = false # false/true - -# How to indent goto labels -# >0 : absolute column where 1 is the leftmost column -# <=0 : subtract from brace indent -indent_label = 2 # number - -# Same as indent_label, but for access specifiers that are followed by a colon -indent_access_spec = -1 # number - -# Indent the code after an access specifier by one level. -# If set, this option forces 'indent_access_spec=0' -indent_access_spec_body = false # false/true - -# If an open paren is followed by a newline, indent the next line so that it lines up after the open paren (not recommended) -indent_paren_nl = false # false/true - -# Controls the indent of a close paren after a newline. -# 0: Indent to body level -# 1: Align under the open paren -# 2: Indent to the brace level -indent_paren_close = 0 # number - -# Controls the indent of a comma when inside a paren.If TRUE, aligns under the open paren -indent_comma_paren = false # false/true - -# Controls the indent of a BOOL operator when inside a paren.If TRUE, aligns under the open paren -indent_bool_paren = false # false/true - -# If 'indent_bool_paren' is true, controls the indent of the first expression. If TRUE, aligns the first expression to the following ones -indent_first_bool_expr = false # false/true - -# If an open square is followed by a newline, indent the next line so that it lines up after the open square (not recommended) -indent_square_nl = false # false/true - -# Don't change the relative indent of ESQL/C 'EXEC SQL' bodies -indent_preserve_sql = false # false/true - -# Align continued statements at the '='. Default=True -# If FALSE or the '=' is followed by a newline, the next line is indent one tab. -indent_align_assign = true # false/true - -# Indent OC blocks at brace level instead of usual rules. -indent_oc_block = false # false/true - -# Indent OC blocks in a message relative to the parameter name. -# 0=use indent_oc_block rules, 1+=spaces to indent -indent_oc_block_msg = 0 # number - -# Minimum indent for subsequent parameters -indent_oc_msg_colon = 0 # number - -# -# Spacing options -# - -# Add or remove space around arithmetic operator '+', '-', '/', '*', etc -sp_arith = force # ignore/add/remove/force - -# Add or remove space around assignment operator '=', '+=', etc -sp_assign = force # ignore/add/remove/force - -# Add or remove space around '=' in C++11 lambda capture specifications. Overrides sp_assign -sp_cpp_lambda_assign = ignore # ignore/add/remove/force - -# Add or remove space after the capture specification in C++11 lambda. -sp_cpp_lambda_paren = ignore # ignore/add/remove/force - -# Add or remove space around assignment operator '=' in a prototype -sp_assign_default = force # ignore/add/remove/force - -# Add or remove space before assignment operator '=', '+=', etc. Overrides sp_assign. -sp_before_assign = force # ignore/add/remove/force - -# Add or remove space after assignment operator '=', '+=', etc. Overrides sp_assign. -sp_after_assign = force # ignore/add/remove/force - -# Add or remove space around assignment '=' in enum -sp_enum_assign = force # ignore/add/remove/force - -# Add or remove space before assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_before_assign = force # ignore/add/remove/force - -# Add or remove space after assignment '=' in enum. Overrides sp_enum_assign. -sp_enum_after_assign = force # ignore/add/remove/force - -# Add or remove space around preprocessor '##' concatenation operator. Default=Add -sp_pp_concat = force # ignore/add/remove/force - -# Add or remove space after preprocessor '#' stringify operator. Also affects the '#@' charizing operator. -sp_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space before preprocessor '#' stringify operator as in '#define x(y) L#y'. -sp_before_pp_stringify = ignore # ignore/add/remove/force - -# Add or remove space around boolean operators '&&' and '||' -sp_bool = force # ignore/add/remove/force - -# Add or remove space around compare operator '<', '>', '==', etc -sp_compare = force # ignore/add/remove/force - -# Add or remove space inside '(' and ')' -sp_inside_paren = remove # ignore/add/remove/force - -# Add or remove space between nested parens -sp_paren_paren = remove # ignore/add/remove/force - -# Whether to balance spaces inside nested parens -sp_balance_nested_parens = false # false/true - -# Add or remove space between ')' and '{' -sp_paren_brace = force # ignore/add/remove/force - -# Add or remove space before pointer star '*' -sp_before_ptr_star = remove # ignore/add/remove/force - -# Add or remove space before pointer star '*' that isn't followed by a variable name -# If set to 'ignore', sp_before_ptr_star is used instead. -sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force - -# Add or remove space between pointer stars '*' -sp_between_ptr_star = remove # ignore/add/remove/force - -# Add or remove space after pointer star '*', if followed by a word. -sp_after_ptr_star = force # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by a func proto/def. -sp_after_ptr_star_func = force # ignore/add/remove/force - -# Add or remove space after a pointer star '*', if followed by an open paren (function types). -sp_ptr_star_paren = ignore # ignore/add/remove/force - -# Add or remove space before a pointer star '*', if followed by a func proto/def. -sp_before_ptr_star_func = remove # ignore/add/remove/force - -# Add or remove space before a reference sign '&' -sp_before_byref = remove # ignore/add/remove/force - -# Add or remove space before a reference sign '&' that isn't followed by a variable name -# If set to 'ignore', sp_before_byref is used instead. -sp_before_unnamed_byref = ignore # ignore/add/remove/force - -# Add or remove space after reference sign '&', if followed by a word. -sp_after_byref = force # ignore/add/remove/force - -# Add or remove space after a reference sign '&', if followed by a func proto/def. -sp_after_byref_func = force # ignore/add/remove/force - -# Add or remove space before a reference sign '&', if followed by a func proto/def. -sp_before_byref_func = force # ignore/add/remove/force - -# Add or remove space between type and word. Default=Force -sp_after_type = force # ignore/add/remove/force - -# Add or remove space before the paren in the D constructs 'template Foo(' and 'class Foo('. -sp_before_template_paren = ignore # ignore/add/remove/force - -# Add or remove space in 'template <' vs 'template<'. -# If set to ignore, sp_before_angle is used. -sp_template_angle = force # ignore/add/remove/force - -# Add or remove space before '<>' -sp_before_angle = remove # ignore/add/remove/force - -# Add or remove space inside '<' and '>' -sp_inside_angle = remove # ignore/add/remove/force - -# Add or remove space after '<>' -sp_after_angle = remove # ignore/add/remove/force - -# Add or remove space between '<>' and '(' as found in 'new List();' -sp_angle_paren = remove # ignore/add/remove/force - -# Add or remove space between '<>' and a word as in 'List m;' -sp_angle_word = force # ignore/add/remove/force - -# Add or remove space between '>' and '>' in '>>' (template stuff C++/C# only). Default=Add -sp_angle_shift = force # ignore/add/remove/force - -# Permit removal of the space between '>>' in 'foo >' (C++11 only). Default=False -# sp_angle_shift cannot remove the space without this option. -sp_permit_cpp11_shift = false # false/true - -# Add or remove space before '(' of 'if', 'for', 'switch', and 'while' -sp_before_sparen = force # ignore/add/remove/force - -# Add or remove space inside if-condition '(' and ')' -sp_inside_sparen = remove # ignore/add/remove/force - -# Add or remove space before if-condition ')'. Overrides sp_inside_sparen. -sp_inside_sparen_close = remove # ignore/add/remove/force - -# Add or remove space before if-condition '('. Overrides sp_inside_sparen. -sp_inside_sparen_open = ignore # ignore/add/remove/force - -# Add or remove space after ')' of 'if', 'for', 'switch', and 'while' -sp_after_sparen = force # ignore/add/remove/force - -# Add or remove space between ')' and '{' of 'if', 'for', 'switch', and 'while' -sp_sparen_brace = force # ignore/add/remove/force - -# Add or remove space between 'invariant' and '(' in the D language. -sp_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space after the ')' in 'invariant (C) c' in the D language. -sp_after_invariant_paren = ignore # ignore/add/remove/force - -# Add or remove space before empty statement ';' on 'if', 'for' and 'while' -sp_special_semi = force # ignore/add/remove/force - -# Add or remove space before ';'. Default=Remove -sp_before_semi = remove # ignore/add/remove/force - -# Add or remove space before ';' in non-empty 'for' statements -sp_before_semi_for = remove # ignore/add/remove/force - -# Add or remove space before a semicolon of an empty part of a for statement. -sp_before_semi_for_empty = force # ignore/add/remove/force - -# Add or remove space after ';', except when followed by a comment. Default=Add -sp_after_semi = add # ignore/add/remove/force - -# Add or remove space after ';' in non-empty 'for' statements. Default=Force -sp_after_semi_for = force # ignore/add/remove/force - -# Add or remove space after the final semicolon of an empty part of a for statement: for ( ; ; ). -sp_after_semi_for_empty = force # ignore/add/remove/force - -# Add or remove space before '[' (except '[]') -sp_before_square = remove # ignore/add/remove/force - -# Add or remove space before '[]' -sp_before_squares = remove # ignore/add/remove/force - -# Add or remove space inside a non-empty '[' and ']' -sp_inside_square = remove # ignore/add/remove/force - -# Add or remove space after ',' -sp_after_comma = force # ignore/add/remove/force - -# Add or remove space before ',' -sp_before_comma = remove # ignore/add/remove/force - -# Add or remove space between an open paren and comma: '(,' vs '( ,' -sp_paren_comma = force # ignore/add/remove/force - -# Add or remove space before the variadic '...' when preceded by a non-punctuator -sp_before_ellipsis = ignore # ignore/add/remove/force - -# Add or remove space after class ':' -sp_after_class_colon = force # ignore/add/remove/force - -# Add or remove space before class ':' -sp_before_class_colon = force # ignore/add/remove/force - -# Add or remove space before case ':'. Default=Remove -sp_before_case_colon = remove # ignore/add/remove/force - -# Add or remove space between 'operator' and operator sign -sp_after_operator = remove # ignore/add/remove/force - -# Add or remove space between the operator symbol and the open paren, as in 'operator ++(' -sp_after_operator_sym = force # ignore/add/remove/force - -# Add or remove space after C/D cast, i.e. 'cast(int)a' vs 'cast(int) a' or '(int)a' vs '(int) a' -sp_after_cast = remove # ignore/add/remove/force - -# Add or remove spaces inside cast parens -sp_inside_paren_cast = remove # ignore/add/remove/force - -# Add or remove space between the type and open paren in a C++ cast, i.e. 'int(exp)' vs 'int (exp)' -sp_cpp_cast_paren = remove # ignore/add/remove/force - -# Add or remove space between 'sizeof' and '(' -sp_sizeof_paren = remove # ignore/add/remove/force - -# Add or remove space after the tag keyword (Pawn) -sp_after_tag = ignore # ignore/add/remove/force - -# Add or remove space inside enum '{' and '}' -sp_inside_braces_enum = force # ignore/add/remove/force - -# Add or remove space inside struct/union '{' and '}' -sp_inside_braces_struct = force # ignore/add/remove/force - -# Add or remove space inside '{' and '}' -sp_inside_braces = force # ignore/add/remove/force - -# Add or remove space inside '{}' -sp_inside_braces_empty = force # ignore/add/remove/force - -# Add or remove space between return type and function name -# A minimum of 1 is forced except for pointer return types. -sp_type_func = force # ignore/add/remove/force - -# Add or remove space between function name and '(' on function declaration -sp_func_proto_paren = remove # ignore/add/remove/force - -# Add or remove space between function name and '(' on function definition -sp_func_def_paren = remove # ignore/add/remove/force - -# Add or remove space inside empty function '()' -sp_inside_fparens = remove # ignore/add/remove/force - -# Add or remove space inside function '(' and ')' -sp_inside_fparen = remove # ignore/add/remove/force - -# Add or remove space inside the first parens in the function type: 'void (*x)(...)' -sp_inside_tparen = ignore # ignore/add/remove/force - -# Add or remove between the parens in the function type: 'void (*x)(...)' -sp_after_tparen_close = ignore # ignore/add/remove/force - -# Add or remove space between ']' and '(' when part of a function call. -sp_square_fparen = remove # ignore/add/remove/force - -# Add or remove space between ')' and '{' of function -sp_fparen_brace = force # ignore/add/remove/force - -# Add or remove space between function name and '(' on function calls -sp_func_call_paren = remove # ignore/add/remove/force - -# Add or remove space between function name and '()' on function calls without parameters. -# If set to 'ignore' (the default), sp_func_call_paren is used. -sp_func_call_paren_empty = ignore # ignore/add/remove/force - -# Add or remove space between the user function name and '(' on function calls -# You need to set a keyword to be a user function, like this: 'set func_call_user _' in the config file. -sp_func_call_user_paren = remove # ignore/add/remove/force - -# Add or remove space between a constructor/destructor and the open paren -sp_func_class_paren = remove # ignore/add/remove/force - -# Add or remove space between 'return' and '(' -sp_return_paren = force # ignore/add/remove/force - -# Add or remove space between '__attribute__' and '(' -sp_attribute_paren = force # ignore/add/remove/force - -# Add or remove space between 'defined' and '(' in '#if defined (FOO)' -sp_defined_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'throw' and '(' in 'throw (something)' -sp_throw_paren = force # ignore/add/remove/force - -# Add or remove space between 'throw' and anything other than '(' as in '@throw [...];' -sp_after_throw = ignore # ignore/add/remove/force - -# Add or remove space between 'catch' and '(' in 'catch (something) { }' -# If set to ignore, sp_before_sparen is used. -sp_catch_paren = force # ignore/add/remove/force - -# Add or remove space between 'version' and '(' in 'version (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_version_paren = ignore # ignore/add/remove/force - -# Add or remove space between 'scope' and '(' in 'scope (something) { }' (D language) -# If set to ignore, sp_before_sparen is used. -sp_scope_paren = ignore # ignore/add/remove/force - -# Add or remove space between macro and value -sp_macro = ignore # ignore/add/remove/force - -# Add or remove space between macro function ')' and value -sp_macro_func = ignore # ignore/add/remove/force - -# Add or remove space between 'else' and '{' if on the same line -sp_else_brace = force # ignore/add/remove/force - -# Add or remove space between '}' and 'else' if on the same line -sp_brace_else = force # ignore/add/remove/force - -# Add or remove space between '}' and the name of a typedef on the same line -sp_brace_typedef = force # ignore/add/remove/force - -# Add or remove space between 'catch' and '{' if on the same line -sp_catch_brace = force # ignore/add/remove/force - -# Add or remove space between '}' and 'catch' if on the same line -sp_brace_catch = force # ignore/add/remove/force - -# Add or remove space between 'finally' and '{' if on the same line -sp_finally_brace = force # ignore/add/remove/force - -# Add or remove space between '}' and 'finally' if on the same line -sp_brace_finally = force # ignore/add/remove/force - -# Add or remove space between 'try' and '{' if on the same line -sp_try_brace = force # ignore/add/remove/force - -# Add or remove space between get/set and '{' if on the same line -sp_getset_brace = ignore # ignore/add/remove/force - -# Add or remove space between a variable and '{' for C++ uniform initialization -sp_word_brace = add # ignore/add/remove/force - -# Add or remove space between a variable and '{' for a namespace -sp_word_brace_ns = add # ignore/add/remove/force - -# Add or remove space before the '::' operator -sp_before_dc = remove # ignore/add/remove/force - -# Add or remove space after the '::' operator -sp_after_dc = remove # ignore/add/remove/force - -# Add or remove around the D named array initializer ':' operator -sp_d_array_colon = ignore # ignore/add/remove/force - -# Add or remove space after the '!' (not) operator. Default=Remove -sp_not = ignore # ignore/add/remove/force - -# Add or remove space after the '~' (invert) operator. Default=Remove -sp_inv = remove # ignore/add/remove/force - -# Add or remove space after the '&' (address-of) operator. Default=Remove -# This does not affect the spacing after a '&' that is part of a type. -sp_addr = remove # ignore/add/remove/force - -# Add or remove space around the '.' or '->' operators. Default=Remove -sp_member = remove # ignore/add/remove/force - -# Add or remove space after the '*' (dereference) operator. Default=Remove -# This does not affect the spacing after a '*' that is part of a type. -sp_deref = remove # ignore/add/remove/force - -# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. Default=Remove -sp_sign = remove # ignore/add/remove/force - -# Add or remove space before or after '++' and '--', as in '(--x)' or 'y++;'. Default=Remove -sp_incdec = remove # ignore/add/remove/force - -# Add or remove space before a backslash-newline at the end of a line. Default=Add -sp_before_nl_cont = force # ignore/add/remove/force - -# Add or remove space after the scope '+' or '-', as in '-(void) foo;' or '+(int) bar;' -sp_after_oc_scope = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '-(int) f:(int) x;' vs '-(int) f: (int) x;' -sp_after_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '-(int) f: (int) x;' vs '-(int) f : (int) x;' -sp_before_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_after_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in immutable dictionary expression -# 'NSDictionary *test = @{@"foo" :@"bar"};' -sp_before_oc_dict_colon = ignore # ignore/add/remove/force - -# Add or remove space after the colon in message specs -# '[object setValue:1];' vs '[object setValue: 1];' -sp_after_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space before the colon in message specs -# '[object setValue:1];' vs '[object setValue :1];' -sp_before_send_oc_colon = ignore # ignore/add/remove/force - -# Add or remove space after the (type) in message specs -# '-(int)f: (int) x;' vs '-(int)f: (int)x;' -sp_after_oc_type = ignore # ignore/add/remove/force - -# Add or remove space after the first (type) in message specs -# '-(int) f:(int)x;' vs '-(int)f:(int)x;' -sp_after_oc_return_type = ignore # ignore/add/remove/force - -# Add or remove space between '@selector' and '(' -# '@selector(msgName)' vs '@selector (msgName)' -# Also applies to @protocol() constructs -sp_after_oc_at_sel = ignore # ignore/add/remove/force - -# Add or remove space between '@selector(x)' and the following word -# '@selector(foo) a:' vs '@selector(foo)a:' -sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space inside '@selector' parens -# '@selector(foo)' vs '@selector( foo )' -# Also applies to @protocol() constructs -sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force - -# Add or remove space before a block pointer caret -# '^int (int arg){...}' vs. ' ^int (int arg){...}' -sp_before_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space after a block pointer caret -# '^int (int arg){...}' vs. '^ int (int arg){...}' -sp_after_oc_block_caret = ignore # ignore/add/remove/force - -# Add or remove space between the receiver and selector in a message. -# '[receiver selector ...]' -sp_after_oc_msg_receiver = ignore # ignore/add/remove/force - -# Add or remove space after @property. -sp_after_oc_property = ignore # ignore/add/remove/force - -# Add or remove space around the ':' in 'b ? t : f' -sp_cond_colon = force # ignore/add/remove/force - -# Add or remove space before the ':' in 'b ? t : f'. Overrides sp_cond_colon. -sp_cond_colon_before = force # ignore/add/remove/force - -# Add or remove space after the ':' in 'b ? t : f'. Overrides sp_cond_colon. -sp_cond_colon_after = force # ignore/add/remove/force - -# Add or remove space around the '?' in 'b ? t : f' -sp_cond_question = force # ignore/add/remove/force - -# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make sense here. -sp_case_label = force # ignore/add/remove/force - -# Control the space around the D '..' operator. -sp_range = ignore # ignore/add/remove/force - -# Control the spacing after ':' in 'for (TYPE VAR : EXPR)' (Java) -sp_after_for_colon = ignore # ignore/add/remove/force - -# Control the spacing before ':' in 'for (TYPE VAR : EXPR)' (Java) -sp_before_for_colon = ignore # ignore/add/remove/force - -# Control the spacing in 'extern (C)' (D) -sp_extern_paren = ignore # ignore/add/remove/force - -# Control the space after the opening of a C++ comment '// A' vs '//A' -sp_cmt_cpp_start = add # ignore/add/remove/force - -# Controls the spaces between #else or #endif and a trailing comment -sp_endif_cmt = ignore # ignore/add/remove/force - -# Controls the spaces after 'new', 'delete', and 'delete[]' -sp_after_new = add # ignore/add/remove/force - -# Controls the spaces before a trailing or embedded comment -sp_before_tr_emb_cmt = add # ignore/add/remove/force - -# Number of spaces before a trailing or embedded comment -sp_num_before_tr_emb_cmt = 2 # number - -# Control space between a Java annotation and the open paren. -sp_annotation_paren = ignore # ignore/add/remove/force - -# -# Code alignment (not left column spaces/tabs) -# - -# Whether to keep non-indenting tabs -align_keep_tabs = false # false/true - -# Whether to use tabs for aligning -align_with_tabs = false # false/true - -# Whether to bump out to the next tab when aligning -align_on_tabstop = false # false/true - -# Whether to left-align numbers -align_number_left = false # false/true - -# Whether to keep whitespace not required for alignment. -align_keep_extra_space = false # false/true - -# Align variable definitions in prototypes and functions -align_func_params = false # false/true - -# Align parameters in single-line functions that have the same name. -# The function names must already be aligned with each other. -align_same_func_call_params = false # false/true - -# The span for aligning variable definitions (0=don't align) -align_var_def_span = 0 # number - -# How to align the star in variable definitions. -# 0=Part of the type 'void * foo;' -# 1=Part of the variable 'void *foo;' -# 2=Dangling 'void *foo;' -align_var_def_star_style = 0 # number - -# How to align the '&' in variable definitions. -# 0=Part of the type -# 1=Part of the variable -# 2=Dangling -align_var_def_amp_style = 0 # number - -# The threshold for aligning variable definitions (0=no limit) -align_var_def_thresh = 0 # number - -# The gap for aligning variable definitions -align_var_def_gap = 0 # number - -# Whether to align the colon in struct bit fields -align_var_def_colon = false # false/true - -# Whether to align any attribute after the variable name -align_var_def_attribute = false # false/true - -# Whether to align inline struct/enum/union variable definitions -align_var_def_inline = false # false/true - -# The span for aligning on '=' in assignments (0=don't align) -align_assign_span = 0 # number - -# The threshold for aligning on '=' in assignments (0=no limit) -align_assign_thresh = 0 # number - -# The span for aligning on '=' in enums (0=don't align) -align_enum_equ_span = 0 # number - -# The threshold for aligning on '=' in enums (0=no limit) -align_enum_equ_thresh = 0 # number - -# The span for aligning struct/union (0=don't align) -align_var_struct_span = 0 # number - -# The threshold for aligning struct/union member definitions (0=no limit) -align_var_struct_thresh = 0 # number - -# The gap for aligning struct/union member definitions -align_var_struct_gap = 0 # number - -# The span for aligning struct initializer values (0=don't align) -align_struct_init_span = 0 # number - -# The minimum space between the type and the synonym of a typedef -align_typedef_gap = 0 # number - -# The span for aligning single-line typedefs (0=don't align) -align_typedef_span = 0 # number - -# How to align typedef'd functions with other typedefs -# 0: Don't mix them at all -# 1: align the open paren with the types -# 2: align the function type name with the other type names -align_typedef_func = 0 # number - -# Controls the positioning of the '*' in typedefs. Just try it. -# 0: Align on typedef type, ignore '*' -# 1: The '*' is part of type name: typedef int *pint; -# 2: The '*' is part of the type, but dangling: typedef int *pint; -align_typedef_star_style = 2 # number - -# Controls the positioning of the '&' in typedefs. Just try it. -# 0: Align on typedef type, ignore '&' -# 1: The '&' is part of type name: typedef int &pint; -# 2: The '&' is part of the type, but dangling: typedef int &pint; -align_typedef_amp_style = 2 # number - -# The span for aligning comments that end lines (0=don't align) -align_right_cmt_span = 0 # number - -# If aligning comments, mix with comments after '}' and #endif with less than 3 spaces before the comment -align_right_cmt_mix = false # false/true - -# If a trailing comment is more than this number of columns away from the text it follows, -# it will qualify for being aligned. This has to be > 0 to do anything. -align_right_cmt_gap = 0 # number - -# Align trailing comment at or beyond column N; 'pulls in' comments as a bonus side effect (0=ignore) -align_right_cmt_at_col = 0 # number - -# The span for aligning function prototypes (0=don't align) -align_func_proto_span = 0 # number - -# Minimum gap between the return type and the function name. -align_func_proto_gap = 0 # number - -# Align function protos on the 'operator' keyword instead of what follows -align_on_operator = false # false/true - -# Whether to mix aligning prototype and variable declarations. -# If true, align_var_def_XXX options are used instead of align_func_proto_XXX options. -align_mix_var_proto = false # false/true - -# Align single-line functions with function prototypes, uses align_func_proto_span -align_single_line_func = false # false/true - -# Aligning the open brace of single-line functions. -# Requires align_single_line_func=true, uses align_func_proto_span -align_single_line_brace = false # false/true - -# Gap for align_single_line_brace. -align_single_line_brace_gap = 0 # number - -# The span for aligning ObjC msg spec (0=don't align) -align_oc_msg_spec_span = 0 # number - -# Whether to align macros wrapped with a backslash and a newline. -# This will not work right if the macro contains a multi-line comment. -align_nl_cont = true # false/true - -# # Align macro functions and variables together -align_pp_define_together = false # false/true - -# The minimum space between label and value of a preprocessor define -align_pp_define_gap = 0 # number - -# The span for aligning on '#define' bodies (0=don't align) -align_pp_define_span = 0 # number - -# Align lines that start with '<<' with previous '<<'. Default=true -align_left_shift = true # false/true - -# Span for aligning parameters in an Obj-C message call on the ':' (0=don't align) -align_oc_msg_colon_span = 0 # number - -# If true, always align with the first parameter, even if it is too short. -align_oc_msg_colon_first = false # false/true - -# Aligning parameters in an Obj-C '+' or '-' declaration on the ':' -align_oc_decl_colon = false # false/true - -# -# Newline adding and removing options -# - -# Whether to collapse empty blocks between '{' and '}' -nl_collapse_empty_body = true # false/true - -# Don't split one-line braced assignments - 'foo_t f = { 1, 2 };' -nl_assign_leave_one_liners = false # false/true - -# Don't split one-line braced statements inside a class xx { } body -nl_class_leave_one_liners = false # false/true - -# Don't split one-line enums: 'enum foo { BAR = 15 };' -nl_enum_leave_one_liners = true # false/true - -# Don't split one-line get or set functions -nl_getset_leave_one_liners = false # false/true - -# Don't split one-line function definitions - 'int foo() { return 0; }' -nl_func_leave_one_liners = false # false/true - -# Don't split one-line if/else statements - 'if(a) b++;' -nl_if_leave_one_liners = false # false/true - -# Don't split one-line OC messages -nl_oc_msg_leave_one_liner = false # false/true - -# Add or remove newlines at the start of the file -nl_start_of_file = remove # ignore/add/remove/force - -# The number of newlines at the start of the file (only used if nl_start_of_file is 'add' or 'force' -nl_start_of_file_min = 0 # number - -# Add or remove newline at the end of the file -nl_end_of_file = force # ignore/add/remove/force - -# The number of newlines at the end of the file (only used if nl_end_of_file is 'add' or 'force') -nl_end_of_file_min = 1 # number - -# Add or remove newline between '=' and '{' -nl_assign_brace = ignore # ignore/add/remove/force - -# Add or remove newline between '=' and '[' (D only) -nl_assign_square = ignore # ignore/add/remove/force - -# Add or remove newline after '= [' (D only). Will also affect the newline before the ']' -nl_after_square_assign = ignore # ignore/add/remove/force - -# The number of blank lines after a block of variable definitions at the top of a function body -# 0 = No change (default) -nl_func_var_def_blk = 0 # number - -# The number of newlines before a block of typedefs -# 0 = No change (default) -nl_typedef_blk_start = 0 # number - -# The number of newlines after a block of typedefs -# 0 = No change (default) -nl_typedef_blk_end = 0 # number - -# The maximum consecutive newlines within a block of typedefs -# 0 = No change (default) -nl_typedef_blk_in = 0 # number - -# The number of newlines before a block of variable definitions not at the top of a function body -# 0 = No change (default) -nl_var_def_blk_start = 0 # number - -# The number of newlines after a block of variable definitions not at the top of a function body -# 0 = No change (default) -nl_var_def_blk_end = 0 # number - -# The maximum consecutive newlines within a block of variable definitions -# 0 = No change (default) -nl_var_def_blk_in = 0 # number - -# Add or remove newline between a function call's ')' and '{', as in: -# list_for_each(item, &list) { } -nl_fcall_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'enum' and '{' -nl_enum_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'struct and '{' -nl_struct_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'union' and '{' -nl_union_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'if' and '{' -nl_if_brace = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'else' -nl_brace_else = remove # ignore/add/remove/force - -# Add or remove newline between 'else if' and '{' -# If set to ignore, nl_if_brace is used instead -nl_elseif_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'else' and '{' -nl_else_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'else' and 'if' -nl_else_if = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'finally' -nl_brace_finally = remove # ignore/add/remove/force - -# Add or remove newline between 'finally' and '{' -nl_finally_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'try' and '{' -nl_try_brace = remove # ignore/add/remove/force - -# Add or remove newline between get/set and '{' -nl_getset_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'for' and '{' -nl_for_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'catch' and '{' -nl_catch_brace = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'catch' -nl_brace_catch = remove # ignore/add/remove/force - -# Add or remove newline between 'while' and '{' -nl_while_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'scope (x)' and '{' (D) -nl_scope_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'unittest' and '{' (D) -nl_unittest_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'version (x)' and '{' (D) -nl_version_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'using' and '{' -nl_using_brace = remove # ignore/add/remove/force - -# Add or remove newline between two open or close braces. -# Due to general newline/brace handling, REMOVE may not work. -nl_brace_brace = ignore # ignore/add/remove/force - -# Add or remove newline between 'do' and '{' -nl_do_brace = remove # ignore/add/remove/force - -# Add or remove newline between '}' and 'while' of 'do' statement -nl_brace_while = remove # ignore/add/remove/force - -# Add or remove newline between 'switch' and '{' -nl_switch_brace = remove # ignore/add/remove/force - -# Add a newline between ')' and '{' if the ')' is on a different line than the if/for/etc. -# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch, and nl_catch_brace. -nl_multi_line_cond = false # false/true - -# Force a newline in a define after the macro name for multi-line defines. -nl_multi_line_define = false # false/true - -# Whether to put a newline before 'case' statement -nl_before_case = false # false/true - -# Add or remove newline between ')' and 'throw' -nl_before_throw = ignore # ignore/add/remove/force - -# Whether to put a newline after 'case' statement -nl_after_case = false # false/true - -# Add or remove a newline between a case ':' and '{'. Overrides nl_after_case. -nl_case_colon_brace = ignore # ignore/add/remove/force - -# Newline between namespace and { -nl_namespace_brace = remove # ignore/add/remove/force - -# Add or remove newline between 'template<>' and whatever follows. -nl_template_class = force # ignore/add/remove/force - -# Add or remove newline between 'class' and '{' -nl_class_brace = remove # ignore/add/remove/force - -# Add or remove newline after each ',' in the constructor member initialization -nl_class_init_args = add # ignore/add/remove/force -nl_constr_init_args = force # ignore/add/remove/force - -# Add or remove newline between return type and function name in a function definition -nl_func_type_name = ignore # ignore/add/remove/force - -# Add or remove newline between return type and function name inside a class {} -# Uses nl_func_type_name or nl_func_proto_type_name if set to ignore. -nl_func_type_name_class = remove # ignore/add/remove/force - -# Add or remove newline between function scope and name in a definition -# Controls the newline after '::' in 'void A::f() { }' -nl_func_scope_name = remove # ignore/add/remove/force - -# Add or remove newline between return type and function name in a prototype -nl_func_proto_type_name = remove # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' -nl_func_paren = remove # ignore/add/remove/force - -# Add or remove newline between a function name and the opening '(' in the definition -nl_func_def_paren = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function declaration -nl_func_decl_start = remove # ignore/add/remove/force - -# Add or remove newline after '(' in a function definition -nl_func_def_start = remove # ignore/add/remove/force - -# Overrides nl_func_decl_start when there is only one parameter. -nl_func_decl_start_single = remove # ignore/add/remove/force - -# Overrides nl_func_def_start when there is only one parameter. -nl_func_def_start_single = remove # ignore/add/remove/force - -# Add or remove newline after each ',' in a function declaration -nl_func_decl_args = ignore # ignore/add/remove/force - -# Add or remove newline after each ',' in a function definition -nl_func_def_args = ignore # ignore/add/remove/force - -# Add or remove newline before the ')' in a function declaration -nl_func_decl_end = remove # ignore/add/remove/force - -# Add or remove newline before the ')' in a function definition -nl_func_def_end = remove # ignore/add/remove/force - -# Overrides nl_func_decl_end when there is only one parameter. -nl_func_decl_end_single = remove # ignore/add/remove/force - -# Overrides nl_func_def_end when there is only one parameter. -nl_func_def_end_single = remove # ignore/add/remove/force - -# Add or remove newline between '()' in a function declaration. -nl_func_decl_empty = remove # ignore/add/remove/force - -# Add or remove newline between '()' in a function definition. -nl_func_def_empty = remove # ignore/add/remove/force - -# Whether to put each OC message parameter on a separate line -# See nl_oc_msg_leave_one_liner -nl_oc_msg_args = false # false/true - -# Add or remove newline between function signature and '{' -nl_fdef_brace = remove # ignore/add/remove/force - -# Add or remove newline between C++11 lambda signature and '{' -nl_cpp_ldef_brace = ignore # ignore/add/remove/force - -# Whether to put a newline after 'return' statement -nl_after_return = false # false/true - -# Add or remove a newline between the return keyword and return expression. -nl_return_expr = remove # ignore/add/remove/force - -# Whether to put a newline after semicolons, except in 'for' statements -nl_after_semicolon = true # false/true - -# Whether to put a newline after brace open. -# This also adds a newline before the matching brace close. -nl_after_brace_open = false # false/true - -# If nl_after_brace_open and nl_after_brace_open_cmt are true, a newline is -# placed between the open brace and a trailing single-line comment. -nl_after_brace_open_cmt = false # false/true - -# Whether to put a newline after a virtual brace open with a non-empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open = false # false/true - -# Whether to put a newline after a virtual brace open with an empty body. -# These occur in un-braced if/while/do/for statement bodies. -nl_after_vbrace_open_empty = false # false/true - -# Whether to put a newline after a brace close. -# Does not apply if followed by a necessary ';'. -nl_after_brace_close = false # false/true - -# Whether to put a newline after a virtual brace close. -# Would add a newline before return in: 'if (foo) a++; return;' -nl_after_vbrace_close = false # false/true - -# Control the newline between the close brace and 'b' in: 'struct { int a; } b;' -# Affects enums, unions, and structures. If set to ignore, uses nl_after_brace_close -nl_brace_struct_var = ignore # ignore/add/remove/force - -# Whether to alter newlines in '#define' macros -nl_define_macro = false # false/true - -# Whether to not put blanks after '#ifxx', '#elxx', or before '#endif' -nl_squeeze_ifdef = false # false/true - -# Add or remove blank line before 'if' -nl_before_if = ignore # ignore/add/remove/force - -# Add or remove blank line after 'if' statement -nl_after_if = ignore # ignore/add/remove/force - -# Add or remove blank line before 'for' -nl_before_for = ignore # ignore/add/remove/force - -# Add or remove blank line after 'for' statement -nl_after_for = ignore # ignore/add/remove/force - -# Add or remove blank line before 'while' -nl_before_while = ignore # ignore/add/remove/force - -# Add or remove blank line after 'while' statement -nl_after_while = ignore # ignore/add/remove/force - -# Add or remove blank line before 'switch' -nl_before_switch = ignore # ignore/add/remove/force - -# Add or remove blank line after 'switch' statement -nl_after_switch = ignore # ignore/add/remove/force - -# Add or remove blank line before 'do' -nl_before_do = ignore # ignore/add/remove/force - -# Add or remove blank line after 'do/while' statement -nl_after_do = ignore # ignore/add/remove/force - -# Whether to double-space commented-entries in struct/enum -nl_ds_struct_enum_cmt = false # false/true - -# Whether to double-space before the close brace of a struct/union/enum -# (lower priority than 'eat_blanks_before_close_brace') -nl_ds_struct_enum_close_brace = false # false/true - -# Add or remove a newline around a class colon. -# Related to pos_class_colon, nl_class_init_args, and pos_comma. -nl_class_colon = ignore # ignore/add/remove/force -nl_constr_colon = force # ignore/add/remove/force -# Change simple unbraced if statements into a one-liner -# 'if(b)\n i++;' => 'if(b) i++;' -nl_create_if_one_liner = false # false/true - -# Change simple unbraced for statements into a one-liner -# 'for (i=0;i<5;i++)\n foo(i);' => 'for (i=0;i<5;i++) foo(i);' -nl_create_for_one_liner = false # false/true - -# Change simple unbraced while statements into a one-liner -# 'while (i<5)\n foo(i++);' => 'while (i<5) foo(i++);' -nl_create_while_one_liner = false # false/true - -# -# Positioning options -# - -# The position of arithmetic operators in wrapped expressions -pos_arith = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of assignment in wrapped expressions. -# Do not affect '=' followed by '{' -pos_assign = trail # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of boolean operators in wrapped expressions -pos_bool = trail # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of comparison operators in wrapped expressions -pos_compare = ignore # ignore/join/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of conditional (b ? t : f) operators in wrapped expressions -pos_conditional = trail # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in wrapped expressions -pos_comma = ignore # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of the comma in the constructor initialization list -pos_class_comma = trail_force # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force -pos_constr_comma = trail_force # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# The position of colons between constructor and member initialization -pos_class_colon = trail_break # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force -pos_constr_colon = trail_force # ignore/lead/lead_break/lead_force/trail/trail_break/trail_force - -# -# Line Splitting options -# - -# Try to limit code width to N number of columns -code_width = 0 # number - -# Whether to fully split long 'for' statements at semi-colons -ls_for_split_full = true # false/true - -# Whether to fully split long function protos/calls at commas -ls_func_split_full = true # false/true - -# Whether to split lines as close to code_width as possible and ignore some groupings -ls_code_width = false # false/true - -# -# Blank line options -# - -# The maximum consecutive newlines -nl_max = 2 # number - -# The number of newlines after a function prototype, if followed by another function prototype -nl_after_func_proto = 0 # number - -# The number of newlines after a function prototype, if not followed by another function prototype -nl_after_func_proto_group = 0 # number - -# The number of newlines after '}' of a multi-line function body -nl_after_func_body = 0 # number - -# The number of newlines after '}' of a multi-line function body in a class declaration -nl_after_func_body_class = 0 # number - -# The number of newlines after '}' of a single line function body -nl_after_func_body_one_liner = 0 # number - -# The minimum number of newlines before a multi-line comment. -# Doesn't apply if after a brace open or another multi-line comment. -nl_before_block_comment = 0 # number - -# The minimum number of newlines before a single-line C comment. -# Doesn't apply if after a brace open or other single-line C comments. -nl_before_c_comment = 0 # number - -# The minimum number of newlines before a CPP comment. -# Doesn't apply if after a brace open or other CPP comments. -nl_before_cpp_comment = 0 # number - -# Whether to force a newline after a multi-line comment. -nl_after_multiline_comment = false # false/true - -# The number of newlines after '}' or ';' of a struct/enum/union definition -nl_after_struct = 0 # number - -# The number of newlines after '}' or ';' of a class definition -nl_after_class = 0 # number - -# The number of newlines before a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. -# Will not change the newline count if after a brace open. -# 0 = No change. -nl_before_access_spec = 2 # number - -# The number of newlines after a 'private:', 'public:', 'protected:', 'signals:', or 'slots:' label. -# 0 = No change. -nl_after_access_spec = 1 # number - -# The number of newlines between a function def and the function comment. -# 0 = No change. -nl_comment_func_def = 0 # number - -# The number of newlines after a try-catch-finally block that isn't followed by a brace close. -# 0 = No change. -nl_after_try_catch_finally = 0 # number - -# The number of newlines before and after a property, indexer or event decl. -# 0 = No change. -nl_around_cs_property = 0 # number - -# The number of newlines between the get/set/add/remove handlers in C#. -# 0 = No change. -nl_between_get_set = 0 # number - -# Add or remove newline between C# property and the '{' -nl_property_brace = ignore # ignore/add/remove/force - -# Whether to remove blank lines after '{' -eat_blanks_after_open_brace = true # false/true - -# Whether to remove blank lines before '}' -eat_blanks_before_close_brace = true # false/true - -# How aggressively to remove extra newlines not in preproc. -# 0: No change -# 1: Remove most newlines not handled by other config -# 2: Remove all newlines and reformat completely by config -nl_remove_extra_newlines = 0 # number - -# Whether to put a blank line before 'return' statements, unless after an open brace. -nl_before_return = false # false/true - -# Whether to put a blank line after 'return' statements, unless followed by a close brace. -nl_after_return = false # false/true - -# Whether to put a newline after a Java annotation statement. -# Only affects annotations that are after a newline. -nl_after_annotation = ignore # ignore/add/remove/force - -# Controls the newline between two annotations. -nl_between_annotation = ignore # ignore/add/remove/force - -# -# Code modifying options (non-whitespace) -# - -# Add or remove braces on single-line 'do' statement -mod_full_brace_do = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'for' statement -mod_full_brace_for = ignore # ignore/add/remove/force - -# Add or remove braces on single-line function definitions. (Pawn) -mod_full_brace_function = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'if' statement. Will not remove the braces if they contain an 'else'. -mod_full_brace_if = ignore # ignore/add/remove/force - -# Make all if/elseif/else statements in a chain be braced or not. Overrides mod_full_brace_if. -# If any must be braced, they are all braced. If all can be unbraced, then the braces are removed. -mod_full_brace_if_chain = false # false/true - -# Don't remove braces around statements that span N newlines -mod_full_brace_nl = 0 # number - -# Add or remove braces on single-line 'while' statement -mod_full_brace_while = ignore # ignore/add/remove/force - -# Add or remove braces on single-line 'using ()' statement -mod_full_brace_using = ignore # ignore/add/remove/force - -# Add or remove unnecessary paren on 'return' statement -mod_paren_on_return = ignore # ignore/add/remove/force - -# Whether to change optional semicolons to real semicolons -mod_pawn_semicolon = false # false/true - -# Add parens on 'while' and 'if' statement around bools -mod_full_paren_if_bool = false # false/true - -# Whether to remove superfluous semicolons -mod_remove_extra_semicolon = true # false/true - -# If a function body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_function_closebrace_comment = 0 # number - -# If a switch body exceeds the specified number of newlines and doesn't have a comment after -# the close brace, a comment will be added. -mod_add_long_switch_closebrace_comment = 0 # number - -# If an #ifdef body exceeds the specified number of newlines and doesn't have a comment after -# the #endif, a comment will be added. -mod_add_long_ifdef_endif_comment = 0 # number - -# If an #ifdef or #else body exceeds the specified number of newlines and doesn't have a comment after -# the #else, a comment will be added. -mod_add_long_ifdef_else_comment = 0 # number - -# If TRUE, will sort consecutive single-line 'import' statements [Java, D] -mod_sort_import = false # false/true - -# If TRUE, will sort consecutive single-line 'using' statements [C#] -mod_sort_using = false # false/true - -# If TRUE, will sort consecutive single-line '#include' statements [C/C++] and '#import' statements [Obj-C] -# This is generally a bad idea, as it may break your code. -mod_sort_include = true # false/true - -# If TRUE, it will move a 'break' that appears after a fully braced 'case' before the close brace. -mod_move_case_break = false # false/true - -# Will add or remove the braces around a fully braced case statement. -# Will only remove the braces if there are no variable declarations in the block. -mod_case_brace = remove # ignore/add/remove/force - -# If TRUE, it will remove a void 'return;' that appears as the last statement in a function. -mod_remove_empty_return = true # false/true - -# -# Comment modifications -# - -# Try to wrap comments at cmt_width columns -cmt_width = 0 # number - -# Set the comment reflow mode (default: 0) -# 0: no reflowing (apart from the line wrapping due to cmt_width) -# 1: no touching at all -# 2: full reflow -cmt_reflow_mode = 0 # number - -# If false, disable all multi-line comment changes, including cmt_width. keyword substitution, and leading chars. -# Default is true. -cmt_indent_multi = false # false/true - -# Whether to group c-comments that look like they are in a block -cmt_c_group = false # false/true - -# Whether to put an empty '/*' on the first line of the combined c-comment -cmt_c_nl_start = false # false/true - -# Whether to put a newline before the closing '*/' of the combined c-comment -cmt_c_nl_end = false # false/true - -# Whether to group cpp-comments that look like they are in a block -cmt_cpp_group = false # false/true - -# Whether to put an empty '/*' on the first line of the combined cpp-comment -cmt_cpp_nl_start = false # false/true - -# Whether to put a newline before the closing '*/' of the combined cpp-comment -cmt_cpp_nl_end = false # false/true - -# Whether to change cpp-comments into c-comments -cmt_cpp_to_c = false # false/true - -# Whether to put a star on subsequent comment lines -cmt_star_cont = false # false/true - -# The number of spaces to insert at the start of subsequent comment lines -cmt_sp_before_star_cont = 0 # number - -# The number of spaces to insert after the star on subsequent comment lines -cmt_sp_after_star_cont = 0 # number - -# For multi-line comments with a '*' lead, remove leading spaces if the first and last lines of -# the comment are the same length. Default=True -cmt_multi_check_last = true # false/true - -# The filename that contains text to insert at the head of a file if the file doesn't start with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_header = "fileheader.txt" # string - -# The filename that contains text to insert at the end of a file if the file doesn't end with a C/C++ comment. -# Will substitute $(filename) with the current file's name. -cmt_insert_file_footer = "" # string - -# The filename that contains text to insert before a function implementation if the function isn't preceded with a C/C++ comment. -# Will substitute $(function) with the function name and $(javaparam) with the javadoc @param and @return stuff. -# Will also substitute $(fclass) with the class name: void CFoo::Bar() { ... } -cmt_insert_func_header = "" # string - -# The filename that contains text to insert before a class if the class isn't preceded with a C/C++ comment. -# Will substitute $(class) with the class name. -cmt_insert_class_header = "" # string - -# The filename that contains text to insert before a Obj-C message specification if the method isn't preceeded with a C/C++ comment. -# Will substitute $(message) with the function name and $(javaparam) with the javadoc @param and @return stuff. -cmt_insert_oc_msg_header = "" # string - -# If a preprocessor is encountered when stepping backwards from a function name, then -# this option decides whether the comment should be inserted. -# Affects cmt_insert_oc_msg_header, cmt_insert_func_header and cmt_insert_class_header. -cmt_insert_before_preproc = false # false/true - -# -# Preprocessor options -# - -# Control indent of preprocessors inside #if blocks at brace level 0 -pp_indent = ignore # ignore/add/remove/force - -# Whether to indent #if/#else/#endif at the brace level (true) or from column 1 (false) -pp_indent_at_level = false # false/true - -# If pp_indent_at_level=false, specifies the number of columns to indent per level. Default=1. -pp_indent_count = 1 # number - -# Add or remove space after # based on pp_level of #if blocks -pp_space = ignore # ignore/add/remove/force - -# Sets the number of spaces added with pp_space -pp_space_count = 0 # number - -# The indent for #region and #endregion in C# and '#pragma region' in C/C++ -pp_indent_region = 0 # number - -# Whether to indent the code between #region and #endregion -pp_region_indent_code = false # false/true - -# If pp_indent_at_level=true, sets the indent for #if, #else, and #endif when not at file-level -pp_indent_if = 0 # number - -# Control whether to indent the code between #if, #else and #endif when not at file-level -pp_if_indent_code = false # false/true - -# Whether to indent '#define' at the brace level (true) or from column 1 (false) -pp_define_at_level = false # false/true - -# You can force a token to be a type with the 'type' option. -# Example: -# type myfoo1 myfoo2 -# -# You can create custom macro-based indentation using macro-open, -# macro-else and macro-close. -# Example: -# macro-open BEGIN_TEMPLATE_MESSAGE_MAP -# macro-open BEGIN_MESSAGE_MAP -# macro-close END_MESSAGE_MAP -# -# You can assign any keyword to any type with the set option. -# set func_call_user _ N_ -# -# The full syntax description of all custom definition config entries -# is shown below: -# -# define custom tokens as: -# - embed whitespace in token using '' escape character, or -# put token in quotes -# - these: ' " and ` are recognized as quote delimiters -# -# type token1 token2 token3 ... -# ^ optionally specify multiple tokens on a single line -# define def_token output_token -# ^ output_token is optional, then NULL is assumed -# macro-open token -# macro-close token -# macro-else token -# set id token1 token2 ... -# ^ optionally specify multiple tokens on a single line -# ^ id is one of the names in token_enum.h sans the CT_ prefix, -# e.g. PP_PRAGMA -# -# all tokens are separated by any mix of ',' commas, '=' equal signs -# and whitespace (space, tab) -# diff --git a/external_tools/WHFC b/external_tools/WHFC deleted file mode 160000 index 5ae2e3664..000000000 --- a/external_tools/WHFC +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 5ae2e3664391ca0db7fab2c82973e98c48937a08 diff --git a/external_tools/googletest b/external_tools/googletest deleted file mode 160000 index 075196ca0..000000000 --- a/external_tools/googletest +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 075196ca060107d44b4e3a1f44b25886ed5bd187 diff --git a/external_tools/growt b/external_tools/growt deleted file mode 160000 index 0c1148ebc..000000000 --- a/external_tools/growt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0c1148ebcdfd4c04803be79706533ad09cc81d37 diff --git a/external_tools/kahypar-shared-resources b/external_tools/kahypar-shared-resources deleted file mode 160000 index 6d5c8e244..000000000 --- a/external_tools/kahypar-shared-resources +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6d5c8e2444e4310667ec1925e995f26179d7ee88 diff --git a/include/helper_functions.h b/include/helper_functions.h index 19cdade2b..9f803f81e 100644 --- a/include/helper_functions.h +++ b/include/helper_functions.h @@ -29,7 +29,7 @@ #include #include -#include "libmtkahypartypes.h" +#include "mtkahypartypes.h" #include "mt-kahypar/partition/context.h" diff --git a/include/libmtkahypar.h b/include/mtkahypar.h similarity index 98% rename from include/libmtkahypar.h rename to include/mtkahypar.h index f0268fd44..f5725bda0 100644 --- a/include/libmtkahypar.h +++ b/include/mtkahypar.h @@ -29,7 +29,7 @@ #include -#include "libmtkahypartypes.h" +#include "mtkahypartypes.h" #ifdef __cplusplus extern "C" { @@ -102,8 +102,7 @@ MT_KAHYPAR_API void mt_kahypar_set_individual_target_block_weights(mt_kahypar_co // ####################### Thread Pool Initialization ####################### -MT_KAHYPAR_API void mt_kahypar_initialize_thread_pool(const size_t num_threads, - const bool interleaved_allocations); +MT_KAHYPAR_API void mt_kahypar_initialize(const size_t num_threads, const bool interleaved_allocations); // ####################### Load/Construct Hypergraph ####################### diff --git a/include/libmtkahypartypes.h b/include/mtkahypartypes.h similarity index 100% rename from include/libmtkahypartypes.h rename to include/mtkahypartypes.h diff --git a/lgtm.yml b/lgtm.yml deleted file mode 100644 index 7d8f39e0e..000000000 --- a/lgtm.yml +++ /dev/null @@ -1,21 +0,0 @@ -path_classifiers: - library: - - external_tools - - codestyle - -queries: - - exclude: external_tools/ - - exclude: codestyle/ - -extraction: - cpp: - after_prepare: - - "mkdir custom_cmake" - - "wget --quiet -O - https://cmake.org/files/v3.16/cmake-3.16.3-Linux-x86_64.tar.gz | tar --strip-components=1 -xz -C custom_cmake" - - "export PATH=$(pwd)/custom_cmake/bin:${PATH}" - index: - build_command: - - cd $LGTM_SRC - - mkdir build; cd build - - cmake .. -DCMAKE_BUILD_TYPE=RELWITHDEBINFO - - make MtKaHyPar diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 204e3ba88..566b7e081 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -1,44 +1,7 @@ -include(GNUInstallDirs) - -add_library(mtkahypar SHARED libmtkahypar.cpp) - -target_link_libraries(mtkahypar TBB::tbb TBB::tbbmalloc_proxy) - -if(KAHYPAR_DOWNLOAD_BOOST) - target_link_libraries(mtkahypar mini_boost) -elseif(NOT MT_KAHYPAR_DISABLE_BOOST) - target_link_libraries(mtkahypar Boost::program_options) +if(BUILD_SHARED_LIBS) + add_library(mtkahypar SHARED mtkahypar.cpp) +else() + add_library(mtkahypar STATIC mtkahypar.cpp) endif() - -target_compile_definitions(mtkahypar PUBLIC MT_KAHYPAR_LIBRARY_MODE) -target_compile_definitions(mtkahypar PUBLIC KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) -target_compile_definitions(mtkahypar PUBLIC KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) -target_compile_definitions(mtkahypar PUBLIC KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) -target_compile_definitions(mtkahypar PUBLIC KAHYPAR_ENABLE_SOED_METRIC) -target_compile_definitions(mtkahypar PUBLIC KAHYPAR_ENABLE_STEINER_TREE_METRIC) - -set(PARTITIONING_SUITE_TARGETS ${PARTITIONING_SUITE_TARGETS} mtkahypar PARENT_SCOPE) - -set_target_properties(mtkahypar PROPERTIES - PUBLIC_HEADER "../include/libmtkahypar.h;../include/libmtkahypartypes.h") - -target_include_directories(mtkahypar SYSTEM PUBLIC ../include) - -configure_file(libmtkahypar.pc.in libmtkahypar.pc @ONLY) - -install(TARGETS mtkahypar - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -install(FILES ${CMAKE_BINARY_DIR}/lib/libmtkahypar.pc - DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) - -configure_file(cmake_uninstall.cmake.in cmake_uninstall.cmake IMMEDIATE @ONLY) - -add_custom_target(uninstall-mtkahypar "${CMAKE_COMMAND}" -P cmake_uninstall.cmake) - -add_custom_target(install.mtkahypar - ${CMAKE_COMMAND} - -DBUILD_TYPE=${CMAKE_BUILD_TYPE} - -P ${CMAKE_BINARY_DIR}/cmake_install.cmake) -ADD_DEPENDENCIES(install.mtkahypar mtkahypar) +target_link_libraries(mtkahypar PRIVATE MtKaHyPar-LibraryBuildSources) +target_include_directories(mtkahypar INTERFACE $) diff --git a/lib/cmake_uninstall.cmake.in b/lib/cmake_uninstall.cmake.in deleted file mode 100644 index c61bc6b16..000000000 --- a/lib/cmake_uninstall.cmake.in +++ /dev/null @@ -1,36 +0,0 @@ -IF(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}") - -SET(NUM 0) -FOREACH(file ${files}) - IF(EXISTS "$ENV{DESTDIR}${file}") - MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - found") - SET(UNINSTALL_CHECK_${NUM} 1) - ELSE(EXISTS "$ENV{DESTDIR}${file}") - MESSAGE(STATUS "Looking for \"$ENV{DESTDIR}${file}\" - not found") - SET(UNINSTALL_CHECK_${NUM} 0) - ENDIF(EXISTS "$ENV{DESTDIR}${file}") - MATH(EXPR NUM "1 + ${NUM}") -ENDFOREACH(file) - -SET(NUM 0) -FOREACH(file ${files}) - IF(${UNINSTALL_CHECK_${NUM}}) - MESSAGE(STATUS "Uninstalling \"$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) - ENDIF(${UNINSTALL_CHECK_${NUM}}) - MATH(EXPR NUM "1 + ${NUM}") -ENDFOREACH(file) - -FILE(REMOVE "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") diff --git a/lib/examples/construct_graph.cc b/lib/examples/construct_graph.cc index 8a23fd699..6d215911a 100644 --- a/lib/examples/construct_graph.cc +++ b/lib/examples/construct_graph.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 construct_graph.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/construct_hypergraph.cc b/lib/examples/construct_hypergraph.cc index 1f3df5545..9940f4bd8 100644 --- a/lib/examples/construct_hypergraph.cc +++ b/lib/examples/construct_hypergraph.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 construct_graph.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/improve_partition.cc b/lib/examples/improve_partition.cc index 488446fa2..1aab617f8 100644 --- a/lib/examples/improve_partition.cc +++ b/lib/examples/improve_partition.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 improve_partition.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/map_hypergraph_onto_target_graph.cc b/lib/examples/map_hypergraph_onto_target_graph.cc index b8b18dbbe..460276586 100644 --- a/lib/examples/map_hypergraph_onto_target_graph.cc +++ b/lib/examples/map_hypergraph_onto_target_graph.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 map_hypergraph_onto_target_graph.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/partition_graph.cc b/lib/examples/partition_graph.cc index c3be14f37..6a5a2df13 100644 --- a/lib/examples/partition_graph.cc +++ b/lib/examples/partition_graph.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 partition_graph.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/partition_hypergraph.cc b/lib/examples/partition_hypergraph.cc index b9889c3f8..84a4afe1f 100644 --- a/lib/examples/partition_hypergraph.cc +++ b/lib/examples/partition_hypergraph.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 partition_hypergraph.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/partition_with_fixed_vertices.cc b/lib/examples/partition_with_fixed_vertices.cc index dd52e9f03..a9e964ee5 100644 --- a/lib/examples/partition_with_fixed_vertices.cc +++ b/lib/examples/partition_with_fixed_vertices.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 partition_with_fixed_vertices.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/examples/partition_with_individual_block_weights.cc b/lib/examples/partition_with_individual_block_weights.cc index e1230096d..cee90e9ef 100644 --- a/lib/examples/partition_with_individual_block_weights.cc +++ b/lib/examples/partition_with_individual_block_weights.cc @@ -3,14 +3,14 @@ #include #include -#include +#include // Install library interface via 'sudo make install.mtkahypar' in build folder // Compile with: g++ -std=c++14 -DNDEBUG -O3 partition_with_individual_block_weights.cc -o example -lmtkahypar int main(int argc, char* argv[]) { // Initialize thread pool - mt_kahypar_initialize_thread_pool( + mt_kahypar_initialize( std::thread::hardware_concurrency() /* use all available cores */, true /* activate interleaved NUMA allocation policy */ ); diff --git a/lib/libmtkahypar.cpp b/lib/mtkahypar.cpp similarity index 96% rename from lib/libmtkahypar.cpp rename to lib/mtkahypar.cpp index 30d5fbb79..0cb346dc5 100644 --- a/lib/libmtkahypar.cpp +++ b/lib/mtkahypar.cpp @@ -25,8 +25,8 @@ * SOFTWARE. ******************************************************************************/ -#include "include/libmtkahypar.h" -#include "include/libmtkahypartypes.h" +#include "include/mtkahypar.h" +#include "include/mtkahypartypes.h" #include "include/helper_functions.h" #include "tbb/parallel_for.h" @@ -37,6 +37,7 @@ #include "mt-kahypar/partition/metrics.h" #include "mt-kahypar/partition/conversion.h" #include "mt-kahypar/partition/mapping/target_graph.h" +#include "mt-kahypar/partition/registries/registry.h" #include "mt-kahypar/parallel/tbb_initializer.h" #include "mt-kahypar/parallel/stl/scalable_vector.h" #include "mt-kahypar/io/hypergraph_factory.h" @@ -45,10 +46,8 @@ #include "mt-kahypar/macros.h" #include "mt-kahypar/utils/cast.h" #include "mt-kahypar/utils/delete.h" - -#ifndef MT_KAHYPAR_DISABLE_BOOST #include "mt-kahypar/io/command_line_options.h" -#endif + using namespace mt_kahypar; @@ -89,8 +88,6 @@ void mt_kahypar_free_context(mt_kahypar_context_t* context) { delete reinterpret_cast(context); } -#ifndef MT_KAHYPAR_DISABLE_BOOST - void mt_kahypar_configure_context_from_file(mt_kahypar_context_t* kahypar_context, const char* ini_file_name) { try { @@ -100,8 +97,6 @@ void mt_kahypar_configure_context_from_file(mt_kahypar_context_t* kahypar_contex } } -#endif - void mt_kahypar_load_preset(mt_kahypar_context_t* context, const mt_kahypar_preset_type_t preset) { Context& c = *reinterpret_cast(context); @@ -181,27 +176,34 @@ void mt_kahypar_set_individual_target_block_weights(mt_kahypar_context_t* contex } } -void mt_kahypar_initialize_thread_pool(const size_t num_threads, - const bool interleaved_allocations) { +void mt_kahypar_initialize(const size_t num_threads, const bool interleaved_allocations) { size_t P = num_threads; - size_t num_available_cpus = HardwareTopology::instance().num_cpus(); - if ( num_available_cpus < num_threads ) { - WARNING("There are currently only" << num_available_cpus << "cpus available." - << "Setting number of threads from" << num_threads - << "to" << num_available_cpus); - P = num_available_cpus; - } + #ifndef KAHYPAR_DISABLE_HWLOC + size_t num_available_cpus = HardwareTopology::instance().num_cpus(); + if ( num_available_cpus < num_threads ) { + WARNING("There are currently only" << num_available_cpus << "cpus available." + << "Setting number of threads from" << num_threads + << "to" << num_available_cpus); + P = num_available_cpus; + } + #endif // Initialize TBB task arenas on numa nodes TBBInitializer::instance(P); - if ( interleaved_allocations ) { - // We set the membind policy to interleaved allocations in order to - // distribute allocations evenly across NUMA nodes - hwloc_cpuset_t cpuset = TBBInitializer::instance().used_cpuset(); - parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); - hwloc_bitmap_free(cpuset); - } + #ifndef KAHYPAR_DISABLE_HWLOC + if ( interleaved_allocations ) { + // We set the membind policy to interleaved allocations in order to + // distribute allocations evenly across NUMA nodes + hwloc_cpuset_t cpuset = TBBInitializer::instance().used_cpuset(); + parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); + hwloc_bitmap_free(cpuset); + } + #else + unused(interleaved_allocations); + #endif + + register_algorithms_and_policies(); } mt_kahypar_hypergraph_t mt_kahypar_read_hypergraph_from_file(const char* file_name, diff --git a/mt-kahypar/CMakeLists.txt b/mt-kahypar/CMakeLists.txt index 76ae5502f..79a5e3d91 100644 --- a/mt-kahypar/CMakeLists.txt +++ b/mt-kahypar/CMakeLists.txt @@ -3,7 +3,5 @@ add_subdirectory(datastructures) add_subdirectory(io) add_subdirectory(utils) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_precompile_headers(${modtarget} PRIVATE definitions.h) - target_precompile_headers(${modtarget} PRIVATE partition/context.h) -endforeach() \ No newline at end of file +target_precompile_headers(MtKaHyPar-Sources INTERFACE definitions.h) +target_precompile_headers(MtKaHyPar-Sources INTERFACE partition/context.h) diff --git a/mt-kahypar/application/CMakeLists.txt b/mt-kahypar/application/CMakeLists.txt index 49af59e0f..c926774a2 100644 --- a/mt-kahypar/application/CMakeLists.txt +++ b/mt-kahypar/application/CMakeLists.txt @@ -1,12 +1,7 @@ add_executable(MtKaHyPar mt_kahypar.cc) -target_link_libraries(MtKaHyPar ${Boost_LIBRARIES}) -target_link_libraries(MtKaHyPar TBB::tbb TBB::tbbmalloc_proxy) -target_link_libraries(MtKaHyPar pthread) -set_property(TARGET MtKaHyPar PROPERTY CXX_STANDARD 17) -set_property(TARGET MtKaHyPar PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(MtKaHyPar MtKaHyPar-BuildSources) -if(ENABLE_PROFILE MATCHES ON) - target_link_libraries(MtKaHyPar ${PROFILE_FLAGS}) -endif() -set(PARTITIONING_SUITE_TARGETS ${PARTITIONING_SUITE_TARGETS} MtKaHyPar PARENT_SCOPE) \ No newline at end of file +# additional installation target since installation-time renaming does not seem to be possible +add_executable(MtKaHyPar-CLI mt_kahypar.cc) +target_link_libraries(MtKaHyPar-CLI MtKaHyPar-BuildSources) diff --git a/mt-kahypar/application/git_revision.txt.in b/mt-kahypar/application/git_revision.txt.in deleted file mode 100644 index e69de29bb..000000000 diff --git a/mt-kahypar/application/mt_kahypar.cc b/mt-kahypar/application/mt_kahypar.cc index 994222ad3..677fe3c8f 100644 --- a/mt-kahypar/application/mt_kahypar.cc +++ b/mt-kahypar/application/mt_kahypar.cc @@ -34,6 +34,7 @@ #include "mt-kahypar/io/presets.h" #include "mt-kahypar/partition/partitioner_facade.h" #include "mt-kahypar/partition/registries/register_memory_pool.h" +#include "mt-kahypar/partition/registries/registry.h" #include "mt-kahypar/partition/conversion.h" #include "mt-kahypar/partition/mapping/target_graph.h" #include "mt-kahypar/utils/cast.h" @@ -78,22 +79,26 @@ int main(int argc, char* argv[]) { context.shared_memory.shuffle_block_size); } - size_t num_available_cpus = HardwareTopology::instance().num_cpus(); - if ( num_available_cpus < context.shared_memory.num_threads ) { - WARNING("There are currently only" << num_available_cpus << "cpus available." - << "Setting number of threads from" << context.shared_memory.num_threads - << "to" << num_available_cpus); - context.shared_memory.num_threads = num_available_cpus; - } + #ifndef KAHYPAR_DISABLE_HWLOC + size_t num_available_cpus = HardwareTopology::instance().num_cpus(); + if ( num_available_cpus < context.shared_memory.num_threads ) { + WARNING("There are currently only" << num_available_cpus << "cpus available." + << "Setting number of threads from" << context.shared_memory.num_threads + << "to" << num_available_cpus); + context.shared_memory.num_threads = num_available_cpus; + } + #endif // Initialize TBB task arenas on numa nodes TBBInitializer::instance(context.shared_memory.num_threads); - // We set the membind policy to interleaved allocations in order to - // distribute allocations evenly across NUMA nodes - hwloc_cpuset_t cpuset = TBBInitializer::instance().used_cpuset(); - parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); - hwloc_bitmap_free(cpuset); + #ifndef KAHYPAR_DISABLE_HWLOC + // We set the membind policy to interleaved allocations in order to + // distribute allocations evenly across NUMA nodes + hwloc_cpuset_t cpuset = TBBInitializer::instance().used_cpuset(); + parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); + hwloc_bitmap_free(cpuset); + #endif // Read Hypergraph utils::Timer& timer = @@ -124,8 +129,9 @@ int main(int argc, char* argv[]) { timer.stop_timer("read_fixed_vertices"); } - // Initialize Memory Pool + // Initialize Memory Pool and Algorithm/Policy Registries register_memory_pool(hypergraph, context); + register_algorithms_and_policies(); // Partition Hypergraph HighResClockTimepoint start = std::chrono::high_resolution_clock::now(); diff --git a/mt-kahypar/datastructures/CMakeLists.txt b/mt-kahypar/datastructures/CMakeLists.txt index c9d6b1c2f..999697e93 100644 --- a/mt-kahypar/datastructures/CMakeLists.txt +++ b/mt-kahypar/datastructures/CMakeLists.txt @@ -1,38 +1,45 @@ -set(MultilevelDatastructureSources - static_hypergraph_factory.cpp - static_hypergraph.cpp +set(DatastructureSources graph.cpp fixed_vertex_support.cpp) +set(MultilevelDatastructureSources + static_hypergraph_factory.cpp + static_hypergraph.cpp) + set(MultilevelGraphDatastructureSources static_graph_factory.cpp - static_graph.cpp - graph.cpp - fixed_vertex_support.cpp) + static_graph.cpp) set(NLevelDatastructureSources contraction_tree.cpp dynamic_hypergraph.cpp dynamic_hypergraph_factory.cpp - graph.cpp - incident_net_array.cpp - fixed_vertex_support.cpp) + incident_net_array.cpp) set(NLevelGraphDatastructureSources contraction_tree.cpp dynamic_graph.cpp dynamic_graph_factory.cpp - graph.cpp - dynamic_adjacency_array.cpp - fixed_vertex_support.cpp) + dynamic_adjacency_array.cpp) +target_sources(MtKaHyPar-Sources INTERFACE ${DatastructureSources}) +target_sources(MtKaHyPar-Sources INTERFACE ${MultilevelDatastructureSources}) +if(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) + target_sources(MtKaHyPar-Sources INTERFACE ${MultilevelGraphDatastructureSources}) +else() + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${MultilevelGraphDatastructureSources}) +endif() +if(KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) + target_sources(MtKaHyPar-Sources INTERFACE ${NLevelDatastructureSources}) +else() + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${NLevelDatastructureSources}) +endif() +if(KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES AND KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES) + target_sources(MtKaHyPar-Sources INTERFACE ${NLevelGraphDatastructureSources}) +else() + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${NLevelGraphDatastructureSources}) +endif() -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${MultilevelGraphDatastructureSources}) - target_sources(${modtarget} PRIVATE ${NLevelGraphDatastructureSources}) - target_sources(${modtarget} PRIVATE ${MultilevelDatastructureSources}) - target_sources(${modtarget} PRIVATE ${NLevelDatastructureSources}) -endforeach() set(ToolsDatastructureSources static_hypergraph_factory.cpp @@ -49,6 +56,4 @@ set(ToolsDatastructureSources dynamic_adjacency_array.cpp fixed_vertex_support.cpp) -foreach(modtarget IN LISTS TOOLS_TARGETS) - target_sources(${modtarget} PRIVATE ${ToolsDatastructureSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-ToolsSources INTERFACE ${ToolsDatastructureSources}) diff --git a/mt-kahypar/datastructures/buffered_vector.h b/mt-kahypar/datastructures/buffered_vector.h index 86030a68b..72adf9042 100644 --- a/mt-kahypar/datastructures/buffered_vector.h +++ b/mt-kahypar/datastructures/buffered_vector.h @@ -28,6 +28,8 @@ #pragma once #include +#include + #include #include diff --git a/mt-kahypar/datastructures/dynamic_graph.h b/mt-kahypar/datastructures/dynamic_graph.h index 5623f623c..0f91bf8a6 100644 --- a/mt-kahypar/datastructures/dynamic_graph.h +++ b/mt-kahypar/datastructures/dynamic_graph.h @@ -33,7 +33,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "kahypar-resources/meta/mandatory.h" #include "kahypar-resources/datastructure/fast_reset_flag_array.h" diff --git a/mt-kahypar/datastructures/dynamic_hypergraph.h b/mt-kahypar/datastructures/dynamic_hypergraph.h index faf70c5c5..e1ba6693e 100644 --- a/mt-kahypar/datastructures/dynamic_hypergraph.h +++ b/mt-kahypar/datastructures/dynamic_hypergraph.h @@ -32,7 +32,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "kahypar-resources/meta/mandatory.h" #include "kahypar-resources/datastructure/fast_reset_flag_array.h" diff --git a/mt-kahypar/datastructures/graph.cpp b/mt-kahypar/datastructures/graph.cpp index 5b609e67c..91ba7c2d0 100644 --- a/mt-kahypar/datastructures/graph.cpp +++ b/mt-kahypar/datastructures/graph.cpp @@ -161,7 +161,7 @@ namespace mt_kahypar::ds { tbb::enumerable_thread_specific local_max_degree(0); // first pass generating unique coarse arcs to determine coarse node degrees - tbb::parallel_for(0U, num_coarse_nodes, [&](NodeID cu) { + tbb::parallel_for(ID(0), num_coarse_nodes, [&](NodeID cu) { auto& clear_list = clear_lists.local(); ArcWeight volume_cu = 0.0; for (auto i = cluster_bounds[cu]; i < cluster_bounds[cu + 1]; ++i) { @@ -192,7 +192,7 @@ namespace mt_kahypar::ds { coarse_graph._max_degree = local_max_degree.combine([](size_t lhs, size_t rhs) { return std::max(lhs, rhs); }); // second pass generating unique coarse arcs - tbb::parallel_for(0U, num_coarse_nodes, [&](NodeID cu) { + tbb::parallel_for(ID(0), num_coarse_nodes, [&](NodeID cu) { auto& clear_list = clear_lists.local(); for (auto i = cluster_bounds[cu]; i < cluster_bounds[cu+1]; ++i) { for (const Arc& arc : arcsOf(nodes_sorted_by_cluster[i])) { @@ -244,7 +244,7 @@ namespace mt_kahypar::ds { ds::Array>& tmp_pos = _tmp_graph_buffer->tmp_pos; ds::Array>& tmp_indices = _tmp_graph_buffer->tmp_indices; ds::Array>& coarse_node_volumes = _tmp_graph_buffer->tmp_node_volumes; - tbb::parallel_for(0U, static_cast(_num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(_num_nodes), [&](const NodeID u) { ASSERT(static_cast(communities[u]) < _num_nodes); mapping[communities[u]] = UL(1); tmp_pos[u] = 0; @@ -258,7 +258,7 @@ namespace mt_kahypar::ds { // Remap community ids coarse_graph._num_nodes = mapping_prefix_sum.total_sum(); - tbb::parallel_for(0U, static_cast(_num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(_num_nodes), [&](const NodeID u) { communities[u] = mapping_prefix_sum[communities[u]]; }); @@ -269,7 +269,7 @@ namespace mt_kahypar::ds { // the tmp adjacence array. // Compute number of arcs in tmp adjacence array with parallel prefix sum ASSERT(coarse_graph._num_nodes <= coarse_node_volumes.size()); - tbb::parallel_for(0U, static_cast(_num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(_num_nodes), [&](const NodeID u) { const NodeID coarse_u = communities[u]; ASSERT(static_cast(coarse_u) < coarse_graph._num_nodes); coarse_node_volumes[coarse_u] += nodeVolume(u); // not deterministic! @@ -287,7 +287,7 @@ namespace mt_kahypar::ds { // Write all arcs into corresponding tmp adjacence array blocks ds::Array& tmp_arcs = _tmp_graph_buffer->tmp_arcs; ds::Array& valid_arcs = _tmp_graph_buffer->valid_arcs; - tbb::parallel_for(0U, static_cast(_num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(_num_nodes), [&](const NodeID u) { const NodeID coarse_u = communities[u]; ASSERT(static_cast(coarse_u) < coarse_graph._num_nodes); for ( const Arc& arc : arcsOf(u) ) { @@ -306,7 +306,7 @@ namespace mt_kahypar::ds { // Therefore, we sort the arcs according to their endpoints // and aggregate weight of arcs with equal endpoints. tbb::enumerable_thread_specific local_max_degree(0); - tbb::parallel_for(0U, static_cast(coarse_graph._num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(coarse_graph._num_nodes), [&](const NodeID u) { const size_t tmp_arc_start = tmp_indices_prefix_sum[u]; const size_t tmp_arc_end = tmp_indices_prefix_sum[u + 1]; // commented out comparison is needed for deterministic arc weights @@ -353,7 +353,7 @@ namespace mt_kahypar::ds { } }); }, [&] { - tbb::parallel_for(0U, static_cast(coarse_graph._num_nodes), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(coarse_graph._num_nodes), [&](const NodeID u) { const size_t start_index_pos = valid_arcs_prefix_sum[tmp_indices_prefix_sum[u]]; ASSERT(start_index_pos <= coarse_graph._num_arcs); coarse_graph._indices[u] = start_index_pos; @@ -400,7 +400,7 @@ namespace mt_kahypar::ds { // deterministic reduce of node volumes since double addition is not commutative or associative // node volumes are computed in for loop because deterministic reduce does not have dynamic load balancing // whereas for loop does. this important since each node incurs O(degree) time - tbb::parallel_for(0U, NodeID(numNodes()), [&](NodeID u) { computeNodeVolume(u); }); + tbb::parallel_for(ID(0), static_cast(numNodes()), [&](NodeID u) { computeNodeVolume(u); }); auto aggregate_volume = [&](const tbb::blocked_range& r, ArcWeight partial_volume) -> ArcWeight { for (NodeID u = r.begin(); u < r.end(); ++u) { @@ -408,7 +408,7 @@ namespace mt_kahypar::ds { } return partial_volume; }; - auto r = tbb::blocked_range(0U, numNodes(), 1000); + auto r = tbb::blocked_range(ID(0), numNodes(), 1000); _total_volume = tbb::parallel_deterministic_reduce(r, 0.0, aggregate_volume, std::plus<>()); } diff --git a/mt-kahypar/datastructures/hypergraph_common.h b/mt-kahypar/datastructures/hypergraph_common.h index ee7720433..7e148c7aa 100644 --- a/mt-kahypar/datastructures/hypergraph_common.h +++ b/mt-kahypar/datastructures/hypergraph_common.h @@ -30,18 +30,25 @@ #include #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/parallel/stl/scalable_vector.h" -#include "mt-kahypar/parallel/hardware_topology.h" #include "mt-kahypar/parallel/tbb_initializer.h" #include "mt-kahypar/parallel/atomic_wrapper.h" #include "mt-kahypar/datastructures/array.h" +#ifndef KAHYPAR_DISABLE_HWLOC + #include "mt-kahypar/parallel/hardware_topology.h" +#endif + namespace mt_kahypar { -using HardwareTopology = mt_kahypar::parallel::HardwareTopology<>; -using TBBInitializer = mt_kahypar::parallel::TBBInitializer; +#ifndef KAHYPAR_DISABLE_HWLOC + using HardwareTopology = mt_kahypar::parallel::HardwareTopology<>; + using TBBInitializer = mt_kahypar::parallel::TBBInitializer; +#else + using TBBInitializer = mt_kahypar::parallel::SimpleTBBInitializer; +#endif #define UI64(X) static_cast(X) @@ -51,18 +58,20 @@ using RatingType = double; #define ID(X) static_cast(X) using HypernodeID = uint64_t; using HyperedgeID = uint64_t; +// louvain graph +using NodeID = uint64_t; #else #define ID(X) static_cast(X) using HypernodeID = uint32_t; using HyperedgeID = uint32_t; +// louvain graph +using NodeID = uint32_t; #endif using HypernodeWeight = int32_t; using HyperedgeWeight = int32_t; using PartitionID = int32_t; using Gain = HyperedgeWeight; -// Graph Types -using NodeID = uint32_t; using ArcWeight = double; struct Arc { diff --git a/mt-kahypar/datastructures/static_graph.h b/mt-kahypar/datastructures/static_graph.h index 18488b0b4..43ba585f5 100644 --- a/mt-kahypar/datastructures/static_graph.h +++ b/mt-kahypar/datastructures/static_graph.h @@ -32,7 +32,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/datastructures/array.h" diff --git a/mt-kahypar/datastructures/static_hypergraph.h b/mt-kahypar/datastructures/static_hypergraph.h index 3966d0fa3..9d152d2f6 100644 --- a/mt-kahypar/datastructures/static_hypergraph.h +++ b/mt-kahypar/datastructures/static_hypergraph.h @@ -30,7 +30,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/datastructures/array.h" diff --git a/mt-kahypar/definitions.h b/mt-kahypar/definitions.h index 9f0fc7e20..69ae5d28a 100644 --- a/mt-kahypar/definitions.h +++ b/mt-kahypar/definitions.h @@ -29,7 +29,7 @@ #include "kahypar-resources/meta/policy_registry.h" #include "kahypar-resources/meta/typelist.h" -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/datastructures/dynamic_graph.h" diff --git a/mt-kahypar/io/CMakeLists.txt b/mt-kahypar/io/CMakeLists.txt index fac128fd2..59ceb29c4 100644 --- a/mt-kahypar/io/CMakeLists.txt +++ b/mt-kahypar/io/CMakeLists.txt @@ -4,21 +4,14 @@ set(IOSources hypergraph_factory.cpp sql_plottools_serializer.cpp partitioning_output.cpp - presets.cpp) + presets.cpp + command_line_options.cpp) -if(NOT MT_KAHYPAR_DISABLE_BOOST) - list(APPEND IOSources command_line_options.cpp) -endif() - -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${IOSources}) -endforeach() +target_sources(MtKaHyPar-Sources INTERFACE ${IOSources}) set(ToolsIOSources hypergraph_io.cpp hypergraph_factory.cpp partitioning_output.cpp) -foreach(modtarget IN LISTS TOOLS_TARGETS) - target_sources(${modtarget} PRIVATE ${ToolsIOSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-ToolsSources INTERFACE ${ToolsIOSources}) diff --git a/mt-kahypar/io/command_line_options.cpp b/mt-kahypar/io/command_line_options.cpp index 123730748..2542f1394 100644 --- a/mt-kahypar/io/command_line_options.cpp +++ b/mt-kahypar/io/command_line_options.cpp @@ -131,7 +131,7 @@ namespace mt_kahypar { po::value(&context.partition.perform_parallel_recursion_in_deep_multilevel)->value_name("")->default_value(true), "If true, then we perform parallel recursion within the deep multilevel scheme.") ("smallest-maxnet-threshold", - po::value(&context.partition.smallest_large_he_size_threshold)->value_name(""), + po::value(&context.partition.smallest_large_he_size_threshold)->value_name(""), "No hyperedge whose size is smaller than this threshold is removed in the large hyperedge removal step (see maxnet-removal-factor)") ("maxnet-removal-factor", po::value(&context.partition.large_hyperedge_size_threshold_factor)->value_name( @@ -572,8 +572,8 @@ namespace mt_kahypar { &context.refinement.flows.alpha))->value_name(""), "Size constraint for flow problem: (1 + alpha * epsilon) * c(V) / k - c(V_1) (alpha = r-flow-scaling)") ((initial_partitioning ? "i-r-flow-max-num-pins" : "r-flow-max-num-pins"), - po::value((initial_partitioning ? &context.initial_partitioning.refinement.flows.max_num_pins : - &context.refinement.flows.max_num_pins))->value_name(""), + po::value((initial_partitioning ? &context.initial_partitioning.refinement.flows.max_num_pins : + &context.refinement.flows.max_num_pins))->value_name(""), "Maximum number of pins a flow problem is allowed to contain") ((initial_partitioning ? "i-r-flow-find-most-balanced-cut" : "r-flow-find-most-balanced-cut"), po::value((initial_partitioning ? &context.initial_partitioning.refinement.flows.find_most_balanced_cut : diff --git a/mt-kahypar/io/docs/FileFormats.md b/mt-kahypar/io/docs/FileFormats.md new file mode 100644 index 000000000..76cfcefd5 --- /dev/null +++ b/mt-kahypar/io/docs/FileFormats.md @@ -0,0 +1,102 @@ +# File Formats + +The following is an overview of the input and output file formats which are used by Mt-KaHyPar. + +**Important note:** For historical reasons, the hMetis and Metis input formats use indices starting at 1. +However, Mt-KaHyPar converts the indices when reading the files, so that they start at 0. +Any results obtained from the binary or one of the library interfaces will also use indices starting at 0 (i.e., shifted by -1 in comparison to the input file). + +## hMetis Format for Input Hypergraphs + +Per default, Mt-KaHyPar assumes that the input hypergraph is provided in the hMetis format: +[Unweighted Example](tests/instances/unweighted_hypergraph.hgr), [Weighted Example](tests/instances/hypergraph_with_node_and_edge_weights.hgr), [hMetis manual](https://karypis.github.io/glaros/files/sw/hmetis/manual.pdf) + +The general format looks as follows: + +``` +% comment +num_hypergedges num_hypernodes [weight_type] +[hyperedge_weight_1] pin_1 pin_2 ... pin_i +... +[hyperedge_weight_m] pin_1 pin_2 ... pin_j +[hypernode_weight_1] +... +[hypernode_weight_n] +``` + +Any line that starts with ‘%’ is a comment line and is skipped. +The first line is a header containing two or three numbers describing the total number of hyperedges, the total number of hypernodes and the types of weights used by the hypergraph +(00/omitted = unweighted, 10 = node weights, 01 = edge weights, 11 = node and edge weights). + +Afterwards, there is one line for each hyperedge which contains a list of the pins (hypernode IDs) of the hyperedge. +If hyperedge weights are used, there is an additional entry at the start of the line which is the weight of the hyperedge. + +If no hypernode weights are used, this is the end of the file. +Otherwise, there is one line for each hypernode containing a single entry, which is the weight of the hypernode. + +## Metis Format for Input Graphs + +Mt-KaHyPar can also read input *graphs* in Metis format via `--input-file-format=metis`. +Also, target graphs for the Steiner tree metric need to be provided in the Metis format: +[Unweighted Example](tests/instances/unweighted_graph.graph), [Weighted Example](tests/instances/graph_with_node_and_edge_weights.graph), [Metis manual](https://karypis.github.io/glaros/files/sw/metis/manual.pdf) + +**Important note:** Mt-KaHyPar only works on undirected graphs. Therefore, for each edge `u -> v` in the input file there *must be* a corresponding entry for `v -> u` with the same edge weight. + +The general format looks as follows: + +``` +% comment +num_nodes num_edges [weight_type] [num_constraints] +[node_weight_1] neigbor_1 [edge_weight_1] neighbor_2 [edge_weight_2] ... neighbor_i [edge_weight_i] +... +[node_weight_n] neigbor_1 [edge_weight_1] neighbor_2 [edge_weight_2] ... neighbor_j [edge_weight_j] +``` + +Any line that starts with ‘%’ is a comment line and is skipped. +The first line is a header containing two or three numbers describing the total number of nodes, the total number of edges and the types of weights used by the graph +(00/omitted = unweighted, 10 = node weights, 01 = edge weights, 11 = node and edge weights). + +The Metis format also supports multi-dimensional weights/constraints, where the dimension is specified with a fourth header entry. +However, multi-contraint partitioning is currently not supported by Mt-KaHyPar and thus the `num_constraints` entry is *not allowed* in input files. + +Afterwards, there is one line for each node which contains the edges as an adjacency list, i.e., a list of the neighbor nodes (node IDs). +If node weights are used, there is an additional entry at the start of the line which is the weight of the node. +If edge weights are used, the adjacency list contains pairs as entries, with the first number being the node ID and the second number being the edge weight. + +## Partition Output Format + +When outputting the partitioning result via `--write-partition-file=true --partition-output-folder=`, Mt-KaHyPar uses the following format: + +``` +block_ID_1 +... +block_ID_n +``` + +The file contains one line for each (hyper)node. +Each line contains a single number which is the ID of the block that the node is assigned to. + +## hMetis Fix File Format + +When partitioning with fixed vertices via `-f `, Mt-KaHyPar assumes that the fixed vertices are provided in hMetis fix file format: +[hMetis manual](https://karypis.github.io/glaros/files/sw/hmetis/manual.pdf) + +The format looks as follows: + +``` +-1|block_ID_1 +... +-1|block_ID_n +``` + +The file contains one line for each (hyper)node. +Each line contains a single number which is the block ID if the node should be fixed, or -1 if the node can be assigned to any block. + +## Conversion Tools for Other Formats + +While we do not support other graph or hypergraph file formats as direct input, we provide some conversion tools. Each can be built via `make `. + - `MtxToGraph` + - `SnapToHgr` + - `SnapToMetis` + +Furthermore, there are conversion tools from hMetis/Metis format to other formats, which are especially useful for comparison benchmarks to other partitioning algorithms. diff --git a/mt-kahypar/io/hypergraph_factory.cpp b/mt-kahypar/io/hypergraph_factory.cpp index b96b38e3f..b16a38705 100644 --- a/mt-kahypar/io/hypergraph_factory.cpp +++ b/mt-kahypar/io/hypergraph_factory.cpp @@ -69,26 +69,32 @@ mt_kahypar_hypergraph_t readHMetisFile(const std::string& filename, hyperedges_weight, hypernodes_weight, remove_single_pin_hes); switch ( type ) { - case STATIC_GRAPH: - return constructHypergraph( - num_hypernodes, num_hyperedges, hyperedges, - hyperedges_weight.data(), hypernodes_weight.data(), - num_removed_single_pin_hyperedges, stable_construction); - case DYNAMIC_GRAPH: - return constructHypergraph( - num_hypernodes, num_hyperedges, hyperedges, - hyperedges_weight.data(), hypernodes_weight.data(), - num_removed_single_pin_hyperedges, stable_construction); case STATIC_HYPERGRAPH: return constructHypergraph( num_hypernodes, num_hyperedges, hyperedges, hyperedges_weight.data(), hypernodes_weight.data(), num_removed_single_pin_hyperedges, stable_construction); + case STATIC_GRAPH: + ENABLE_GRAPHS( + return constructHypergraph( + num_hypernodes, num_hyperedges, hyperedges, + hyperedges_weight.data(), hypernodes_weight.data(), + num_removed_single_pin_hyperedges, stable_construction); + ) case DYNAMIC_HYPERGRAPH: - return constructHypergraph( - num_hypernodes, num_hyperedges, hyperedges, - hyperedges_weight.data(), hypernodes_weight.data(), - num_removed_single_pin_hyperedges, stable_construction); + ENABLE_HIGHEST_QUALITY( + return constructHypergraph( + num_hypernodes, num_hyperedges, hyperedges, + hyperedges_weight.data(), hypernodes_weight.data(), + num_removed_single_pin_hyperedges, stable_construction); + ) + case DYNAMIC_GRAPH: + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS( + return constructHypergraph( + num_hypernodes, num_hyperedges, hyperedges, + hyperedges_weight.data(), hypernodes_weight.data(), + num_removed_single_pin_hyperedges, stable_construction); + ) case NULLPTR_HYPERGRAPH: return mt_kahypar_hypergraph_t { nullptr, NULLPTR_HYPERGRAPH }; } @@ -107,27 +113,30 @@ mt_kahypar_hypergraph_t readMetisFile(const std::string& filename, readGraphFile(filename, num_edges, num_vertices, edges, edges_weight, nodes_weight); switch ( type ) { - case STATIC_GRAPH: - return constructHypergraph( + case STATIC_HYPERGRAPH: + return constructHypergraph( num_vertices, num_edges, edges, edges_weight.data(), nodes_weight.data(), 0, stable_construction); - case DYNAMIC_GRAPH: - return constructHypergraph( + ENABLE_GRAPHS(case STATIC_GRAPH: + return constructHypergraph( num_vertices, num_edges, edges, edges_weight.data(), nodes_weight.data(), 0, stable_construction); - case STATIC_HYPERGRAPH: - return constructHypergraph( + ) + ENABLE_HIGHEST_QUALITY(case DYNAMIC_HYPERGRAPH: + return constructHypergraph( num_vertices, num_edges, edges, edges_weight.data(), nodes_weight.data(), 0, stable_construction); - case DYNAMIC_HYPERGRAPH: - return constructHypergraph( + ) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case DYNAMIC_GRAPH: + return constructHypergraph( num_vertices, num_edges, edges, edges_weight.data(), nodes_weight.data(), 0, stable_construction); + ) case NULLPTR_HYPERGRAPH: return mt_kahypar_hypergraph_t { nullptr, NULLPTR_HYPERGRAPH }; + default: + return mt_kahypar_hypergraph_t { nullptr, NULLPTR_HYPERGRAPH }; } - - return mt_kahypar_hypergraph_t { nullptr, NULLPTR_HYPERGRAPH }; } } // namespace @@ -169,15 +178,9 @@ namespace { HypernodeID numberOfNodes(mt_kahypar_hypergraph_t hypergraph) { switch ( hypergraph.type ) { case STATIC_HYPERGRAPH: return utils::cast(hypergraph).initialNumNodes(); - #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES - case STATIC_GRAPH: return utils::cast(hypergraph).initialNumNodes(); - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_GRAPH: return utils::cast(hypergraph).initialNumNodes(); - #endif - #endif - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_HYPERGRAPH: return utils::cast(hypergraph).initialNumNodes(); - #endif + ENABLE_GRAPHS(case STATIC_GRAPH: return utils::cast(hypergraph).initialNumNodes();) + ENABLE_HIGHEST_QUALITY(case DYNAMIC_HYPERGRAPH: return utils::cast(hypergraph).initialNumNodes();) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case DYNAMIC_GRAPH: return utils::cast(hypergraph).initialNumNodes();) case NULLPTR_HYPERGRAPH: return 0; default: return 0; } @@ -217,18 +220,15 @@ void addFixedVertices(mt_kahypar_hypergraph_t hypergraph, switch ( hypergraph.type ) { case STATIC_HYPERGRAPH: addFixedVertices(utils::cast(hypergraph), fixed_vertices, k); break; - #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES - case STATIC_GRAPH: + ENABLE_GRAPHS(case STATIC_GRAPH: addFixedVertices(utils::cast(hypergraph), fixed_vertices, k); break; - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_GRAPH: - addFixedVertices(utils::cast(hypergraph), fixed_vertices, k); break; - #endif - #endif - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_HYPERGRAPH: + ) + ENABLE_HIGHEST_QUALITY(case DYNAMIC_HYPERGRAPH: addFixedVertices(utils::cast(hypergraph), fixed_vertices, k); break; - #endif + ) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case DYNAMIC_GRAPH: + addFixedVertices(utils::cast(hypergraph), fixed_vertices, k); break; + ) case NULLPTR_HYPERGRAPH: default: break; } @@ -250,18 +250,15 @@ void removeFixedVertices(mt_kahypar_hypergraph_t hypergraph) { switch ( hypergraph.type ) { case STATIC_HYPERGRAPH: removeFixedVertices(utils::cast(hypergraph)); break; - #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES - case STATIC_GRAPH: + ENABLE_GRAPHS(case STATIC_GRAPH: removeFixedVertices(utils::cast(hypergraph)); break; - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_GRAPH: - removeFixedVertices(utils::cast(hypergraph)); break; - #endif - #endif - #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES - case DYNAMIC_HYPERGRAPH: + ) + ENABLE_HIGHEST_QUALITY(case DYNAMIC_HYPERGRAPH: removeFixedVertices(utils::cast(hypergraph)); break; - #endif + ) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case DYNAMIC_GRAPH: + removeFixedVertices(utils::cast(hypergraph)); break; + ) case NULLPTR_HYPERGRAPH: default: break; } diff --git a/mt-kahypar/io/hypergraph_factory.h b/mt-kahypar/io/hypergraph_factory.h index 3535d3224..a0e333fdb 100644 --- a/mt-kahypar/io/hypergraph_factory.h +++ b/mt-kahypar/io/hypergraph_factory.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/datastructures/hypergraph_common.h" #include "mt-kahypar/partition/context_enum_classes.h" diff --git a/mt-kahypar/io/hypergraph_io.cpp b/mt-kahypar/io/hypergraph_io.cpp index 84415c449..4b9ece891 100644 --- a/mt-kahypar/io/hypergraph_io.cpp +++ b/mt-kahypar/io/hypergraph_io.cpp @@ -36,13 +36,13 @@ #include #include -#if defined(__linux__) or defined(__APPLE__) -#include -#include -#elif _WIN32 +#if _WIN32 #include #include #include +#else +#include +#include #endif @@ -55,26 +55,26 @@ namespace mt_kahypar::io { - #if defined(__linux__) or defined(__APPLE__) + #if _WIN32 struct FileHandle { - int fd; + HANDLE hFile; + HANDLE hMem; char* mapped_file; size_t length; void closeHandle() { - close(fd); + CloseHandle(hFile); + CloseHandle(hMem); } }; - #elif _WIN32 + #else struct FileHandle { - HANDLE hFile; - HANDLE hMem; + int fd; char* mapped_file; size_t length; void closeHandle() { - CloseHandle(hFile); - CloseHandle(hMem); + close(fd); } }; #endif @@ -130,7 +130,7 @@ namespace mt_kahypar::io { if ( handle.mapped_file == NULL ) { throw SystemException("Failed to map file to main memory:" + filename); } - #elif defined(__linux__) or defined(__APPLE__) + #else handle.fd = open(filename.c_str(), O_RDONLY); if ( handle.fd < -1 ) { throw InvalidInputException("Could not open: " + filename); @@ -148,7 +148,7 @@ namespace mt_kahypar::io { void munmap_file(FileHandle& handle) { #ifdef _WIN32 UnmapViewOfFile(handle.mapped_file); - #elif defined(__linux__) or defined(__APPLE__) + #else munmap(handle.mapped_file, handle.length); #endif handle.closeHandle(); diff --git a/mt-kahypar/macros.h b/mt-kahypar/macros.h index 815e14b23..e03e3dbc7 100644 --- a/mt-kahypar/macros.h +++ b/mt-kahypar/macros.h @@ -29,7 +29,7 @@ #include #if defined(MT_KAHYPAR_LIBRARY_MODE) || \ - !defined(KAHYPAR_ENABLE_THREAD_PINNING) || defined(__APPLE__) + !defined(KAHYPAR_ENABLE_THREAD_PINNING) #include // If we use the C or Python interface or thread pinning is disabled, the cpu ID // to which the current thread is assigned to is not unique. We therefore use @@ -37,12 +37,12 @@ // ID can be negative if the task scheduler is not initialized. #define THREAD_ID std::max(0, tbb::this_task_arena::current_thread_index()) #else -#ifdef __linux__ -#include -#define THREAD_ID sched_getcpu() -#elif _WIN32 +#ifdef _WIN32 #include #define THREAD_ID GetCurrentProcessorNumber() +#else +#include +#define THREAD_ID sched_getcpu() #endif #endif diff --git a/mt-kahypar/parallel/memory_pool.h b/mt-kahypar/parallel/memory_pool.h index 0267df9d3..32a70e2bd 100644 --- a/mt-kahypar/parallel/memory_pool.h +++ b/mt-kahypar/parallel/memory_pool.h @@ -34,10 +34,10 @@ #include #include #include -#if defined(__linux__) or defined(__APPLE__) -#include -#elif _WIN32 +#if _WIN32 #include +#else +#include #endif #include @@ -592,12 +592,12 @@ class MemoryPoolT { _use_round_robin_assignment(true), _use_minimum_allocation_size(true), _use_unused_memory_chunks(true) { - #if defined(__linux__) or defined(__APPLE__) - _page_size = sysconf(_SC_PAGE_SIZE); - #elif _WIN32 + #if _WIN32 SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo); _page_size = sysInfo.dwPageSize; + #else + _page_size = sysconf(_SC_PAGE_SIZE); #endif } diff --git a/mt-kahypar/parallel/tbb_initializer.h b/mt-kahypar/parallel/tbb_initializer.h index 0280b60d5..76866c94b 100644 --- a/mt-kahypar/parallel/tbb_initializer.h +++ b/mt-kahypar/parallel/tbb_initializer.h @@ -27,7 +27,10 @@ #pragma once -#include +#ifndef KAHYPAR_DISABLE_HWLOC + #include +#endif + #include #include #include @@ -42,6 +45,8 @@ namespace mt_kahypar { namespace parallel { + +#ifndef KAHYPAR_DISABLE_HWLOC /** * Creates number of NUMA nodes TBB task arenas. Each task arena is pinned * to a unique NUMA node. Each task arena can then be used to execute tasks @@ -56,6 +61,8 @@ class TBBInitializer { using ThreadPinningObserver = mt_kahypar::parallel::ThreadPinningObserver; public: + static constexpr bool provides_numa_information = true; + TBBInitializer(const TBBInitializer&) = delete; TBBInitializer & operator= (const TBBInitializer &) = delete; @@ -145,5 +152,45 @@ class TBBInitializer { std::vector _cpus; std::vector> _numa_node_to_cpu_id; }; + +#else + +class SimpleTBBInitializer { + + public: + static constexpr bool provides_numa_information = false; + + SimpleTBBInitializer(const SimpleTBBInitializer&) = delete; + SimpleTBBInitializer & operator= (const SimpleTBBInitializer &) = delete; + + SimpleTBBInitializer(SimpleTBBInitializer&&) = delete; + SimpleTBBInitializer & operator= (SimpleTBBInitializer &&) = delete; + + static SimpleTBBInitializer& instance(const size_t num_threads = std::thread::hardware_concurrency()) { + static SimpleTBBInitializer instance(num_threads); + return instance; + } + + int num_used_numa_nodes() const { + return 1; + } + + int total_number_of_threads() const { + return _num_threads; + } + + void terminate() { } + + private: + explicit SimpleTBBInitializer(const int num_threads) : + _num_threads(num_threads), + _gc(tbb::global_control::max_allowed_parallelism, num_threads) { } + + int _num_threads; + tbb::global_control _gc; +}; +#endif + + } // namespace parallel } // namespace mt_kahypar diff --git a/mt-kahypar/parallel/thread_pinning_observer.h b/mt-kahypar/parallel/thread_pinning_observer.h index d2e421b13..8fc5f8b9a 100644 --- a/mt-kahypar/parallel/thread_pinning_observer.h +++ b/mt-kahypar/parallel/thread_pinning_observer.h @@ -32,10 +32,10 @@ #include #include -#ifdef __linux__ -#include -#elif _WIN32 +#ifdef _WIN32 #include +#elif KAHYPAR_ENABLE_THREAD_PINNING +#include #endif #undef __TBB_ARENA_OBSERVER @@ -81,7 +81,7 @@ class ThreadPinningObserver : public tbb::task_scheduler_observer { _cpus.push_back(HwTopology::instance().get_backup_cpu(_numa_node, _cpus[0])); } - #if defined(KAHYPAR_ENABLE_THREAD_PINNING) and not defined(__APPLE__) + #if defined(KAHYPAR_ENABLE_THREAD_PINNING) #ifndef MT_KAHYPAR_LIBRARY_MODE observe(true); // Enable thread pinning #endif @@ -172,16 +172,16 @@ class ThreadPinningObserver : public tbb::task_scheduler_observer { private: void pin_thread_to_cpu(const int cpu_id) { - #ifndef __APPLE__ - #if __linux__ + #if KAHYPAR_ENABLE_THREAD_PINNING + #if _WIN32 + auto mask = (static_cast(1) << cpu_id); + const int err = SetThreadAffinityMask(GetCurrentThread(), mask) == 0; + #else const size_t size = CPU_ALLOC_SIZE(_num_cpus); cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(cpu_id, &mask); const int err = sched_setaffinity(0, size, &mask); - #elif _WIN32 - auto mask = (static_cast(1) << cpu_id); - const int err = SetThreadAffinityMask(GetCurrentThread(), mask) == 0; #endif if (err) { @@ -193,6 +193,8 @@ class ThreadPinningObserver : public tbb::task_scheduler_observer { ASSERT(THREAD_ID == cpu_id); DBG << "Thread with PID" << std::this_thread::get_id() << "successfully pinned to CPU" << cpu_id; + #else + unused(cpu_id); #endif } diff --git a/mt-kahypar/partition/CMakeLists.txt b/mt-kahypar/partition/CMakeLists.txt index 1a05c4130..518976188 100644 --- a/mt-kahypar/partition/CMakeLists.txt +++ b/mt-kahypar/partition/CMakeLists.txt @@ -17,9 +17,7 @@ set(PartitionSources recursive_bipartitioning.cpp ) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${PartitionSources}) -endforeach() +target_sources(MtKaHyPar-Sources INTERFACE ${PartitionSources}) set(PartitionToolsSources context.cpp @@ -28,6 +26,4 @@ set(PartitionToolsSources metrics.cpp ) -foreach(modtarget IN LISTS TOOLS_TARGETS) - target_sources(${modtarget} PRIVATE ${PartitionToolsSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-ToolsSources INTERFACE ${PartitionToolsSources}) diff --git a/mt-kahypar/partition/coarsening/CMakeLists.txt b/mt-kahypar/partition/coarsening/CMakeLists.txt index c66311264..36bc0e4c4 100644 --- a/mt-kahypar/partition/coarsening/CMakeLists.txt +++ b/mt-kahypar/partition/coarsening/CMakeLists.txt @@ -5,7 +5,5 @@ set(MultilevelCoarseningSources set(NLevelCoarseningSources nlevel_uncoarsener.cpp) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${MultilevelCoarseningSources}) - target_sources(${modtarget} PRIVATE ${NLevelCoarseningSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-Sources INTERFACE ${MultilevelCoarseningSources}) +target_sources(MtKaHyPar-Sources INTERFACE ${NLevelCoarseningSources}) diff --git a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.h b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.h index 3796ba940..a0630c849 100644 --- a/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.h +++ b/mt-kahypar/partition/coarsening/deterministic_multilevel_coarsener.h @@ -29,7 +29,7 @@ #include "multilevel_coarsener_base.h" #include "i_coarsener.h" -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/utils/reproducible_random.h" #include "mt-kahypar/datastructures/sparse_map.h" diff --git a/mt-kahypar/partition/coarsening/i_coarsener.h b/mt-kahypar/partition/coarsening/i_coarsener.h index eead947c6..b68ea10a9 100644 --- a/mt-kahypar/partition/coarsening/i_coarsener.h +++ b/mt-kahypar/partition/coarsening/i_coarsener.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/partition/refinement/i_refiner.h" diff --git a/mt-kahypar/partition/coarsening/multilevel_coarsener.h b/mt-kahypar/partition/coarsening/multilevel_coarsener.h index 483832f05..0dadc45fc 100644 --- a/mt-kahypar/partition/coarsening/multilevel_coarsener.h +++ b/mt-kahypar/partition/coarsening/multilevel_coarsener.h @@ -36,7 +36,7 @@ #include "kahypar-resources/meta/mandatory.h" -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/partition/coarsening/multilevel_coarsener_base.h" #include "mt-kahypar/partition/coarsening/multilevel_vertex_pair_rater.h" @@ -242,7 +242,7 @@ class MultilevelCoarsener : public ICoarsener, tbb::enumerable_thread_specific num_nodes_update_threshold(0); ds::FixedVertexSupport fixed_vertices = current_hg.copyOfFixedVertexSupport(); fixed_vertices.setMaxBlockWeight(_context.partition.max_part_weights); - tbb::parallel_for(0U, current_hg.initialNumNodes(), [&](const HypernodeID id) { + tbb::parallel_for(ID(0), current_hg.initialNumNodes(), [&](const HypernodeID id) { ASSERT(id < _current_vertices.size()); const HypernodeID hn = _current_vertices[id]; if (current_hg.nodeIsEnabled(hn)) { diff --git a/mt-kahypar/partition/coarsening/nlevel_coarsener.h b/mt-kahypar/partition/coarsening/nlevel_coarsener.h index d05e75495..7032c7ead 100644 --- a/mt-kahypar/partition/coarsening/nlevel_coarsener.h +++ b/mt-kahypar/partition/coarsening/nlevel_coarsener.h @@ -32,7 +32,7 @@ #include #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "kahypar-resources/meta/mandatory.h" #include "mt-kahypar/partition/coarsening/nlevel_coarsener_base.h" diff --git a/mt-kahypar/partition/context.cpp b/mt-kahypar/partition/context.cpp index f634c0704..e2591a1d9 100644 --- a/mt-kahypar/partition/context.cpp +++ b/mt-kahypar/partition/context.cpp @@ -249,7 +249,9 @@ namespace mt_kahypar { std::ostream & operator<< (std::ostream& str, const SharedMemoryParameters& params) { str << "Shared Memory Parameters: " << std::endl; str << " Number of Threads: " << params.num_threads << std::endl; - str << " Number of used NUMA nodes: " << TBBInitializer::instance().num_used_numa_nodes() << std::endl; + if constexpr (TBBInitializer::provides_numa_information) { + str << " Number of used NUMA nodes: " << TBBInitializer::instance().num_used_numa_nodes() << std::endl; + } str << " Use Localized Random Shuffle: " << std::boolalpha << params.use_localized_random_shuffle << std::endl; str << " Random Shuffle Block Size: " << params.shuffle_block_size << std::endl; return str; diff --git a/mt-kahypar/partition/context_enum_classes.cpp b/mt-kahypar/partition/context_enum_classes.cpp index 913dab8b7..919b7db67 100644 --- a/mt-kahypar/partition/context_enum_classes.cpp +++ b/mt-kahypar/partition/context_enum_classes.cpp @@ -27,7 +27,7 @@ #include "context_enum_classes.h" -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/utils/exception.h" diff --git a/mt-kahypar/partition/context_enum_classes.h b/mt-kahypar/partition/context_enum_classes.h index 3d4aefdda..fabfd1dea 100644 --- a/mt-kahypar/partition/context_enum_classes.h +++ b/mt-kahypar/partition/context_enum_classes.h @@ -31,7 +31,7 @@ #include #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" namespace mt_kahypar { diff --git a/mt-kahypar/partition/conversion.h b/mt-kahypar/partition/conversion.h index 19b683da7..7ce48dc23 100644 --- a/mt-kahypar/partition/conversion.h +++ b/mt-kahypar/partition/conversion.h @@ -26,7 +26,7 @@ #pragma once -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/partition/context_enum_classes.h" #include "mt-kahypar/datastructures/hypergraph_common.h" diff --git a/mt-kahypar/partition/initial_partitioning/CMakeLists.txt b/mt-kahypar/partition/initial_partitioning/CMakeLists.txt index 32c2953af..d4f738b2c 100644 --- a/mt-kahypar/partition/initial_partitioning/CMakeLists.txt +++ b/mt-kahypar/partition/initial_partitioning/CMakeLists.txt @@ -5,6 +5,4 @@ set(InitialPartitioningSources label_propagation_initial_partitioner.cpp ) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${InitialPartitioningSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-Sources INTERFACE ${InitialPartitioningSources}) diff --git a/mt-kahypar/partition/initial_partitioning/pool_initial_partitioner.h b/mt-kahypar/partition/initial_partitioning/pool_initial_partitioner.h index 1eb51c18e..a572e21bd 100644 --- a/mt-kahypar/partition/initial_partitioning/pool_initial_partitioner.h +++ b/mt-kahypar/partition/initial_partitioning/pool_initial_partitioner.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/partition/context.h" namespace mt_kahypar { diff --git a/mt-kahypar/partition/mapping/CMakeLists.txt b/mt-kahypar/partition/mapping/CMakeLists.txt index 1e7d5b608..5c63e23ce 100644 --- a/mt-kahypar/partition/mapping/CMakeLists.txt +++ b/mt-kahypar/partition/mapping/CMakeLists.txt @@ -7,28 +7,10 @@ set(MappingSources kerninghan_lin.cpp ) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) - target_sources(${modtarget} PRIVATE ${MappingSources}) - else () - target_sources(mtkahypar PRIVATE ${MappingSources}) - target_sources(mtkahypar_python PRIVATE ${MappingSources}) - endif() -endforeach() +if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) + target_sources(MtKaHyPar-Sources INTERFACE ${MappingSources}) +else () + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${MappingSources}) +endif() -set(ToolsMappingSources - target_graph.cpp - all_pair_shortest_path.cpp - steiner_tree.cpp - ) - -foreach(modtarget IN LISTS TOOLS_TARGETS) - target_sources(${modtarget} PRIVATE ${ToolsMappingSources}) -endforeach() - -set(OneToOneMappingSources - greedy_mapping.cpp - initial_mapping.cpp - kerninghan_lin.cpp - ) -target_sources(OneToOneMapping PRIVATE ${OneToOneMappingSources}) \ No newline at end of file +target_sources(MtKaHyPar-ToolsSources INTERFACE ${MappingSources}) diff --git a/mt-kahypar/partition/mapping/target_graph.cpp b/mt-kahypar/partition/mapping/target_graph.cpp index 3b5c465b4..7164f6a4a 100644 --- a/mt-kahypar/partition/mapping/target_graph.cpp +++ b/mt-kahypar/partition/mapping/target_graph.cpp @@ -66,7 +66,7 @@ HyperedgeWeight TargetGraph::distance(const ds::StaticBitset& connectivity_set) } else { const uint64_t hash_key = computeHash(connectivity_set); // We have not precomputed the optimal steiner tree for the connectivity set. - #ifdef __linux__ + #ifdef KAHYPAR_USE_GROWT HashTableHandle& handle = _handles.local(); auto res = handle.find(hash_key); if ( likely( res != handle.end() ) ) { @@ -80,7 +80,7 @@ HyperedgeWeight TargetGraph::distance(const ds::StaticBitset& connectivity_set) handle.insert(hash_key, mst_weight); return mst_weight; } - #elif defined(_WIN32) or defined(__APPLE__) + #else auto res = _cache.find(hash_key); if ( likely ( res != _cache.end() ) ) { if constexpr ( TRACK_STATS ) ++_stats.cache_hits; diff --git a/mt-kahypar/partition/mapping/target_graph.h b/mt-kahypar/partition/mapping/target_graph.h index 5cfca9dc6..58264cf03 100644 --- a/mt-kahypar/partition/mapping/target_graph.h +++ b/mt-kahypar/partition/mapping/target_graph.h @@ -32,7 +32,7 @@ #include -#ifdef __linux__ +#ifdef KAHYPAR_USE_GROWT #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunused-parameter" @@ -50,7 +50,7 @@ #ifdef __clang__ #pragma clang diagnostic pop #endif -#elif defined(_WIN32) or defined(__APPLE__) +#else #include #endif @@ -71,13 +71,13 @@ class TargetGraph { using PQElement = std::pair; using PQ = std::priority_queue, std::greater>; - #ifdef __linux__ + #ifdef KAHYPAR_USE_GROWT using hasher_type = utils_tm::hash_tm::murmur2_hash; using allocator_type = growt::AlignedAllocator<>; using ConcurrentHashTable = typename growt::table_config< uint64_t, uint64_t, hasher_type, allocator_type, hmod::growable, hmod::sync>::table_type; using HashTableHandle = typename ConcurrentHashTable::handle_type; - #elif defined(_WIN32) or defined(__APPLE__) + #else using ConcurrentHashTable = tbb::concurrent_unordered_map; #endif @@ -114,7 +114,7 @@ class TargetGraph { _distances(), _local_mst_data(graph.initialNumNodes()), _cache(INITIAL_HASH_TABLE_CAPACITY), - #ifdef __linux__ + #ifdef KAHYPAR_USE_GROWT _handles([&]() { return getHandle(); }), #endif _stats() { } @@ -259,7 +259,7 @@ class TargetGraph { bool inputGraphIsConnected() const; - #ifdef __linux__ + #ifdef KAHYPAR_USE_GROWT HashTableHandle getHandle() const { return _cache.get_handle(); } @@ -286,7 +286,7 @@ class TargetGraph { // ! Cache stores the weight of MST computations mutable ConcurrentHashTable _cache; - #ifdef __linux__ + #ifdef KAHYPAR_USE_GROWT // ! Handle to access concurrent hash table mutable tbb::enumerable_thread_specific _handles; #endif diff --git a/mt-kahypar/partition/multilevel.cpp b/mt-kahypar/partition/multilevel.cpp index 8057d8b1c..85165f6f5 100644 --- a/mt-kahypar/partition/multilevel.cpp +++ b/mt-kahypar/partition/multilevel.cpp @@ -31,7 +31,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/definitions.h" #include "mt-kahypar/partition/factories.h" diff --git a/mt-kahypar/partition/partitioner_facade.h b/mt-kahypar/partition/partitioner_facade.h index 1e604f92d..0ee8599f2 100644 --- a/mt-kahypar/partition/partitioner_facade.h +++ b/mt-kahypar/partition/partitioner_facade.h @@ -27,7 +27,7 @@ #pragma once -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/partition/context.h" diff --git a/mt-kahypar/partition/preprocessing/CMakeLists.txt b/mt-kahypar/partition/preprocessing/CMakeLists.txt index 55dab7a5b..4c4db3717 100644 --- a/mt-kahypar/partition/preprocessing/CMakeLists.txt +++ b/mt-kahypar/partition/preprocessing/CMakeLists.txt @@ -2,6 +2,4 @@ set(PreprocessingSources community_detection/parallel_louvain.cpp community_detection/local_moving_modularity.cpp) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${PreprocessingSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-Sources INTERFACE ${PreprocessingSources}) diff --git a/mt-kahypar/partition/preprocessing/community_detection/local_moving_modularity.cpp b/mt-kahypar/partition/preprocessing/community_detection/local_moving_modularity.cpp index 42c67b6d5..452cad623 100644 --- a/mt-kahypar/partition/preprocessing/community_detection/local_moving_modularity.cpp +++ b/mt-kahypar/partition/preprocessing/community_detection/local_moving_modularity.cpp @@ -104,7 +104,7 @@ bool ParallelLocalMovingModularity::localMoving(Graph& g } else { auto& nodes = permutation.permutation; nodes.resize(graph.numNodes()); - tbb::parallel_for(0U, static_cast(graph.numNodes()), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(graph.numNodes()), [&](const NodeID u) { nodes[u] = u; communities[u] = u; _cluster_volumes[u].store(graph.nodeVolume(u), std::memory_order_relaxed); @@ -346,7 +346,7 @@ template void ParallelLocalMovingModularity::initializeClusterVolumes(const Graph& graph, ds::Clustering& communities) { _reciprocal_total_volume = 1.0 / graph.totalVolume(); _vol_multiplier_div_by_node_vol = _reciprocal_total_volume; - tbb::parallel_for(0U, static_cast(graph.numNodes()), [&](const NodeID u) { + tbb::parallel_for(ID(0), static_cast(graph.numNodes()), [&](const NodeID u) { const PartitionID community_id = communities[u]; _cluster_volumes[community_id] += graph.nodeVolume(u); }); diff --git a/mt-kahypar/partition/refinement/CMakeLists.txt b/mt-kahypar/partition/refinement/CMakeLists.txt index 4eb3ef92b..9c8828f1b 100644 --- a/mt-kahypar/partition/refinement/CMakeLists.txt +++ b/mt-kahypar/partition/refinement/CMakeLists.txt @@ -38,37 +38,30 @@ set(SteinerTreeGraphSources gains/steiner_tree_for_graphs/steiner_tree_gain_cache_for_graphs.cpp gains/steiner_tree_for_graphs/steiner_tree_flow_network_construction_for_graphs.cpp) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${RefinementSources}) - target_sources(${modtarget} PRIVATE ${Km1Sources}) - target_sources(${modtarget} PRIVATE ${CutSources}) +target_sources(MtKaHyPar-Sources INTERFACE ${RefinementSources}) +target_sources(MtKaHyPar-Sources INTERFACE ${Km1Sources}) +target_sources(MtKaHyPar-Sources INTERFACE ${CutSources}) - if ( KAHYPAR_ENABLE_SOED_METRIC ) - target_sources(${modtarget} PRIVATE ${SoedSources}) - else () - target_sources(mtkahypar PRIVATE ${SoedSources}) - target_sources(mtkahypar_python PRIVATE ${SoedSources}) - endif() +if ( KAHYPAR_ENABLE_SOED_METRIC ) + target_sources(MtKaHyPar-Sources INTERFACE ${SoedSources}) +else () + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${SoedSources}) +endif() - if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) - target_sources(${modtarget} PRIVATE ${SteinerTreeSources}) - else () - target_sources(mtkahypar PRIVATE ${SteinerTreeSources}) - target_sources(mtkahypar_python PRIVATE ${SteinerTreeSources}) - endif() +if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) + target_sources(MtKaHyPar-Sources INTERFACE ${SteinerTreeSources}) +else () + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${SteinerTreeSources}) +endif() - if ( KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES ) - target_sources(${modtarget} PRIVATE ${CutGraphSources}) - if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) - target_sources(${modtarget} PRIVATE ${SteinerTreeGraphSources}) - else () - target_sources(mtkahypar PRIVATE ${SteinerTreeGraphSources}) - target_sources(mtkahypar_python PRIVATE ${SteinerTreeGraphSources}) - endif() - else () - target_sources(mtkahypar PRIVATE ${CutGraphSources}) - target_sources(mtkahypar_python PRIVATE ${CutGraphSources}) - target_sources(mtkahypar PRIVATE ${SteinerTreeGraphSources}) - target_sources(mtkahypar_python PRIVATE ${SteinerTreeGraphSources}) - endif() -endforeach() +if ( KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES ) + target_sources(MtKaHyPar-Sources INTERFACE ${CutGraphSources}) + if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) + target_sources(MtKaHyPar-Sources INTERFACE ${SteinerTreeGraphSources}) + else () + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${SteinerTreeGraphSources}) + endif() +else () + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${CutGraphSources}) + target_sources(MtKaHyPar-LibraryBuildSources PRIVATE ${SteinerTreeGraphSources}) +endif() diff --git a/mt-kahypar/partition/refinement/flows/i_flow_refiner.h b/mt-kahypar/partition/refinement/flows/i_flow_refiner.h index a38b59c41..7edb56a51 100644 --- a/mt-kahypar/partition/refinement/flows/i_flow_refiner.h +++ b/mt-kahypar/partition/refinement/flows/i_flow_refiner.h @@ -27,7 +27,7 @@ #pragma once -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/definitions.h" #include "mt-kahypar/macros.h" diff --git a/mt-kahypar/partition/refinement/fm/global_rollback.cpp b/mt-kahypar/partition/refinement/fm/global_rollback.cpp index 6931d491a..43f934dd7 100644 --- a/mt-kahypar/partition/refinement/fm/global_rollback.cpp +++ b/mt-kahypar/partition/refinement/fm/global_rollback.cpp @@ -411,7 +411,7 @@ namespace mt_kahypar { last_recalc_round.assign(phg.initialNumEdges(), CAtomic(0)); } } else{ - tbb::parallel_for(0U, phg.initialNumEdges(), recalculate_and_distribute_for_hyperedge); + tbb::parallel_for(ID(0), phg.initialNumEdges(), recalculate_and_distribute_for_hyperedge); } } diff --git a/mt-kahypar/partition/refinement/fm/multitry_kway_fm.cpp b/mt-kahypar/partition/refinement/fm/multitry_kway_fm.cpp index ae0b94de7..324726aa1 100644 --- a/mt-kahypar/partition/refinement/fm/multitry_kway_fm.cpp +++ b/mt-kahypar/partition/refinement/fm/multitry_kway_fm.cpp @@ -371,7 +371,7 @@ namespace mt_kahypar { std::swap(move_tracker.moveOrder, tmp_move_order); move_tracker.runningMoveID.store(first_move_id + next_move_index); - tbb::parallel_for(ID(0), next_move_index, [&](const MoveID move_id) { + tbb::parallel_for(static_cast(0), next_move_index, [&](const MoveID move_id) { const Move& m = move_tracker.moveOrder[move_id]; if (m.isValid()) { move_tracker.moveOfNode[m.node] = first_move_id + move_id; diff --git a/mt-kahypar/partition/refinement/gains/README.md b/mt-kahypar/partition/refinement/gains/README.md index c19432d87..9981f9e13 100644 --- a/mt-kahypar/partition/refinement/gains/README.md +++ b/mt-kahypar/partition/refinement/gains/README.md @@ -18,7 +18,7 @@ At this point, you can run Mt-KaHyPar with your new objective function by adding ## Initial Partitioning -We perform recursive bipartitioning to compute an initial k-way partition. The scheme recursively bipartitions the hypergraph until we reach the desired number of blocks. Each bipartitioning call optimizes the cut metric (weight of all cut nets). However, other objective functions can be optimized implicitly by implementing the two functions defined in ```partition/refinement/gains/bipartitioning_policy.h```. The main invariant of our recursive bipartitioning algorithm is that the cut of all bipartitions sum up to the objective value of the initial k-way partition. There are unit tests that asserts this invariant in ```tests/partition/refinement/bipartitioning_gain_policy_test.cc``` (build test suite via ```make mt_kahypar_tests``` and then run ```./tests/mt_kahypar_tests --gtest_filter=*ABipartitioningPolicy*```). +We perform recursive bipartitioning to compute an initial k-way partition. The scheme recursively bipartitions the hypergraph until we reach the desired number of blocks. Each bipartitioning call optimizes the cut metric (weight of all cut nets). However, other objective functions can be optimized implicitly by implementing the two functions defined in ```partition/refinement/gains/bipartitioning_policy.h```. The main invariant of our recursive bipartitioning algorithm is that the cut of all bipartitions sum up to the objective value of the initial k-way partition. There are unit tests that asserts this invariant in ```tests/partition/refinement/bipartitioning_gain_policy_test.cc``` (build test suite via ```make mtkahypar_tests``` and then run ```./tests/mtkahypar_tests --gtest_filter=*ABipartitioningPolicy*```). ### Cut Net Splitting and Removal @@ -115,7 +115,7 @@ void uncontractUpdateAfterReplacement( ``` The first function is called if ```u``` and ```v``` are both contained in hyperedge ```he``` after the uncontraction. The second function is called if ```v``` replaces ```u``` in hyperedge ```he```. If it is not possible to update the gain cache after the uncontraction operation, you can throw an error/exception in both functions or optimize out the n-level code by adding ```-DKAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES=OFF``` to the cmake build command. However, if you do not implement these functions, it is not possible to use our ```highest_quality``` configuration. -There is a unit test that verifies your gain cache implementation, which you can find in ```tests/partition/refinement/gain_cache_test.cc``` (build test suite via ```make mt_kahypar_tests``` and then run ```./tests/mt_kahypar_tests --gtest_filter=*AGainCache*```). To test your gain cache implementation, you can add your gain type struct to the ```TestConfigs```. +There is a unit test that verifies your gain cache implementation, which you can find in ```tests/partition/refinement/gain_cache_test.cc``` (build test suite via ```make mtkahypar_tests``` and then run ```./tests/mtkahypar_tests --gtest_filter=*AGainCache*```). To test your gain cache implementation, you can add your gain type struct to the ```TestConfigs```. ### Thread-Local Gain Cache @@ -151,9 +151,9 @@ To test your implementation, you can enable logging in our flow-based refinement ### C Interface -- ```include/libmtkahypartypes.h```: Add a enum type to ```mt_kahypar_objective_t``` representing your new objective function -- ```lib/libmtkahypar.cpp```: Create a mapping between the enum types ```mt_kahypar_objective_t``` and ```Objective``` in ```mt_kahypar_set_context_parameter(...)``` and ```mt_kahypar_set_partitioning_parameters(...)``` -- ```include/libmtkahypar.h```: Add a function that takes a ```mt_kahypar_partitioned_hypergraph_t``` and computes your objective function (similar to ```mt_kahypar_cut(...)``` and ```mt_kahypar_km1```). +- ```include/mtkahypartypes.h```: Add a enum type to ```mt_kahypar_objective_t``` representing your new objective function +- ```lib/mtkahypar.cpp```: Create a mapping between the enum types ```mt_kahypar_objective_t``` and ```Objective``` in ```mt_kahypar_set_context_parameter(...)``` and ```mt_kahypar_set_partitioning_parameters(...)``` +- ```include/mtkahypar.h```: Add a function that takes a ```mt_kahypar_partitioned_hypergraph_t``` and computes your objective function (similar to ```mt_kahypar_cut(...)``` and ```mt_kahypar_km1```). ### Python Interface diff --git a/mt-kahypar/partition/refinement/i_rebalancer.h b/mt-kahypar/partition/refinement/i_rebalancer.h index e700f5318..f6c952d1e 100644 --- a/mt-kahypar/partition/refinement/i_rebalancer.h +++ b/mt-kahypar/partition/refinement/i_rebalancer.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/parallel/stl/scalable_vector.h" diff --git a/mt-kahypar/partition/refinement/i_refiner.h b/mt-kahypar/partition/refinement/i_refiner.h index ba50b082c..88687a867 100644 --- a/mt-kahypar/partition/refinement/i_refiner.h +++ b/mt-kahypar/partition/refinement/i_refiner.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/parallel/stl/scalable_vector.h" diff --git a/mt-kahypar/partition/registries/CMakeLists.txt b/mt-kahypar/partition/registries/CMakeLists.txt index 293c477de..3ba0e90bb 100644 --- a/mt-kahypar/partition/registries/CMakeLists.txt +++ b/mt-kahypar/partition/registries/CMakeLists.txt @@ -6,6 +6,4 @@ set(RegistrySources register_initial_partitioning_algorithms.cpp ) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${RegistrySources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-Sources INTERFACE ${RegistrySources}) diff --git a/mt-kahypar/partition/registries/register_coarsening_algorithms.cpp b/mt-kahypar/partition/registries/register_coarsening_algorithms.cpp index 9f7e93f07..c109e5b7d 100644 --- a/mt-kahypar/partition/registries/register_coarsening_algorithms.cpp +++ b/mt-kahypar/partition/registries/register_coarsening_algorithms.cpp @@ -25,6 +25,8 @@ * SOFTWARE. ******************************************************************************/ +#include "register_coarsening_algorithms.h" + #include "kahypar-resources/meta/registrar.h" #include "kahypar-resources/meta/static_multi_dispatch_factory.h" #include "kahypar-resources/meta/typelist.h" @@ -64,7 +66,7 @@ using NLevelCoarsenerDispatcher = kahypar::meta::StaticMultiDispatchFactory register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](mt_kahypar_hypergraph_t hypergraph, const Context& context, uncoarsening_data_t* uncoarseningData) { \ return dispatcher::create( \ @@ -74,33 +76,36 @@ using NLevelCoarsenerDispatcher = kahypar::meta::StaticMultiDispatchFactory::getInstance().getPolicy( - context.partition.partition_type), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.rating_function), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.heavy_node_penalty_policy), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.acceptance_policy)); +void register_coarsening_algorithms() { + REGISTER_DISPATCHED_COARSENER(CoarseningAlgorithm::multilevel_coarsener, + MultilevelCoarsenerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.rating_function), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.heavy_node_penalty_policy), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.acceptance_policy)); -#ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES -REGISTER_DISPATCHED_COARSENER(CoarseningAlgorithm::nlevel_coarsener, - NLevelCoarsenerDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.rating_function), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.heavy_node_penalty_policy), - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.coarsening.rating.acceptance_policy)); -#endif + #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES + REGISTER_DISPATCHED_COARSENER(CoarseningAlgorithm::nlevel_coarsener, + NLevelCoarsenerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.rating_function), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.heavy_node_penalty_policy), + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.coarsening.rating.acceptance_policy)); + #endif + + REGISTER_DISPATCHED_COARSENER(CoarseningAlgorithm::deterministic_multilevel_coarsener, + DeterministicCoarsenerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); -REGISTER_DISPATCHED_COARSENER(CoarseningAlgorithm::deterministic_multilevel_coarsener, - DeterministicCoarsenerDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); +} } // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_coarsening_algorithms.h b/mt-kahypar/partition/registries/register_coarsening_algorithms.h new file mode 100644 index 000000000..1f9628793 --- /dev/null +++ b/mt-kahypar/partition/registries/register_coarsening_algorithms.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2024 Nikolai Maas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#pragma once + +namespace mt_kahypar { + +void register_coarsening_algorithms(); + +} // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.cpp b/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.cpp index 7b6eec76e..4204e076b 100644 --- a/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.cpp +++ b/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.cpp @@ -25,6 +25,8 @@ * SOFTWARE. ******************************************************************************/ +#include "register_initial_partitioning_algorithms.h" + #include "kahypar-resources/meta/static_multi_dispatch_factory.h" #include "kahypar-resources/meta/typelist.h" #include "kahypar-resources/meta/registrar.h" @@ -42,7 +44,7 @@ #define REGISTER_DISPATCHED_INITIAL_PARTITIONER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const InitialPartitioningAlgorithm algorithm, ip_data_container_t* ip_data, \ const Context& context, const int seed, const int tag) { \ @@ -104,40 +106,44 @@ using GreedySequentialMaxNetDispatcher = kahypar::meta::StaticMultiDispatchFacto IInitialPartitioner, kahypar::meta::Typelist>; -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::random, - RandomPartitionerDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::bfs, - BFSPartitionerDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::label_propagation, - LPPartitionerDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_round_robin_fm, - GreedyRoundRobinFMDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_global_fm, - GreedyGlobalFMDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_sequential_fm, - GreedySequentialFMDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_round_robin_max_net, - GreedyRoundRobinMaxNetDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_global_max_net, - GreedyGlobalMaxNetDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); -REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_sequential_max_net, - GreedySequentialMaxNetDispatcher, - kahypar::meta::PolicyRegistry::getInstance().getPolicy( - context.partition.partition_type)); + +void register_initial_partitioning_algorithms() { + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::random, + RandomPartitionerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::bfs, + BFSPartitionerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::label_propagation, + LPPartitionerDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_round_robin_fm, + GreedyRoundRobinFMDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_global_fm, + GreedyGlobalFMDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_sequential_fm, + GreedySequentialFMDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_round_robin_max_net, + GreedyRoundRobinMaxNetDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_global_max_net, + GreedyGlobalMaxNetDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); + REGISTER_DISPATCHED_INITIAL_PARTITIONER(InitialPartitioningAlgorithm::greedy_sequential_max_net, + GreedySequentialMaxNetDispatcher, + kahypar::meta::PolicyRegistry::getInstance().getPolicy( + context.partition.partition_type)); +} + } // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.h b/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.h new file mode 100644 index 000000000..f6b323ccd --- /dev/null +++ b/mt-kahypar/partition/registries/register_initial_partitioning_algorithms.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2024 Nikolai Maas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#pragma once + +namespace mt_kahypar { + +void register_initial_partitioning_algorithms(); + +} // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_policies.cpp b/mt-kahypar/partition/registries/register_policies.cpp index f9ef01b69..5bc2c48f3 100644 --- a/mt-kahypar/partition/registries/register_policies.cpp +++ b/mt-kahypar/partition/registries/register_policies.cpp @@ -25,6 +25,8 @@ * SOFTWARE. ******************************************************************************/ +#include "register_policies.h" + #include "kahypar-resources/meta/policy_registry.h" #include "kahypar-resources/meta/registrar.h" @@ -40,70 +42,73 @@ id, new policy_class()) namespace mt_kahypar { -// ////////////////////////////////////////////////////////////////////////////// -// Hypergraph Type Traits -// ////////////////////////////////////////////////////////////////////////////// -#ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES -REGISTER_POLICY(mt_kahypar_partition_type_t, MULTILEVEL_GRAPH_PARTITIONING, - StaticGraphTypeTraits); -#endif -REGISTER_POLICY(mt_kahypar_partition_type_t, MULTILEVEL_HYPERGRAPH_PARTITIONING, - StaticHypergraphTypeTraits); -#ifdef KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES -REGISTER_POLICY(mt_kahypar_partition_type_t, LARGE_K_PARTITIONING, - LargeKHypergraphTypeTraits); -#endif -#ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES -#ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES -REGISTER_POLICY(mt_kahypar_partition_type_t, N_LEVEL_GRAPH_PARTITIONING, - DynamicGraphTypeTraits); -#endif -REGISTER_POLICY(mt_kahypar_partition_type_t, N_LEVEL_HYPERGRAPH_PARTITIONING, - DynamicHypergraphTypeTraits); -#endif -// ////////////////////////////////////////////////////////////////////////////// -// Coarsening / Rating Policies -// ////////////////////////////////////////////////////////////////////////////// -REGISTER_POLICY(RatingFunction, RatingFunction::heavy_edge, - HeavyEdgeScore); -#ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES -REGISTER_POLICY(RatingFunction, RatingFunction::sameness, - SamenessScore); -#endif +void register_policies() { + // ////////////////////////////////////////////////////////////////////////////// + // Hypergraph Type Traits + // ////////////////////////////////////////////////////////////////////////////// + #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES + REGISTER_POLICY(mt_kahypar_partition_type_t, MULTILEVEL_GRAPH_PARTITIONING, + StaticGraphTypeTraits); + #endif + REGISTER_POLICY(mt_kahypar_partition_type_t, MULTILEVEL_HYPERGRAPH_PARTITIONING, + StaticHypergraphTypeTraits); + #ifdef KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES + REGISTER_POLICY(mt_kahypar_partition_type_t, LARGE_K_PARTITIONING, + LargeKHypergraphTypeTraits); + #endif + #ifdef KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES + #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES + REGISTER_POLICY(mt_kahypar_partition_type_t, N_LEVEL_GRAPH_PARTITIONING, + DynamicGraphTypeTraits); + #endif + REGISTER_POLICY(mt_kahypar_partition_type_t, N_LEVEL_HYPERGRAPH_PARTITIONING, + DynamicHypergraphTypeTraits); + #endif + + // ////////////////////////////////////////////////////////////////////////////// + // Coarsening / Rating Policies + // ////////////////////////////////////////////////////////////////////////////// + REGISTER_POLICY(RatingFunction, RatingFunction::heavy_edge, + HeavyEdgeScore); + #ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES + REGISTER_POLICY(RatingFunction, RatingFunction::sameness, + SamenessScore); + #endif -REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::no_penalty, - NoWeightPenalty); -#ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES -REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::multiplicative_penalty, - MultiplicativePenalty); -REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::additive, - AdditivePenalty); -#endif + REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::no_penalty, + NoWeightPenalty); + #ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES + REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::multiplicative_penalty, + MultiplicativePenalty); + REGISTER_POLICY(HeavyNodePenaltyPolicy, HeavyNodePenaltyPolicy::additive, + AdditivePenalty); + #endif -REGISTER_POLICY(AcceptancePolicy, AcceptancePolicy::best_prefer_unmatched, - BestRatingPreferringUnmatched); -#ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES -REGISTER_POLICY(AcceptancePolicy, AcceptancePolicy::best, - BestRatingWithTieBreaking); -#endif + REGISTER_POLICY(AcceptancePolicy, AcceptancePolicy::best_prefer_unmatched, + BestRatingPreferringUnmatched); + #ifdef KAHYPAR_ENABLE_EXPERIMENTAL_FEATURES + REGISTER_POLICY(AcceptancePolicy, AcceptancePolicy::best, + BestRatingWithTieBreaking); + #endif -// ////////////////////////////////////////////////////////////////////////////// -// Gain Type Policies -// ////////////////////////////////////////////////////////////////////////////// -REGISTER_POLICY(GainPolicy, GainPolicy::km1, Km1GainTypes); -REGISTER_POLICY(GainPolicy, GainPolicy::cut, CutGainTypes); -#ifdef KAHYPAR_ENABLE_SOED_METRIC -REGISTER_POLICY(GainPolicy, GainPolicy::soed, SoedGainTypes); -#endif -#ifdef KAHYPAR_ENABLE_STEINER_TREE_METRIC -REGISTER_POLICY(GainPolicy, GainPolicy::steiner_tree, SteinerTreeGainTypes); -#endif -#ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES -REGISTER_POLICY(GainPolicy, GainPolicy::cut_for_graphs, CutGainForGraphsTypes); -#ifdef KAHYPAR_ENABLE_STEINER_TREE_METRIC -REGISTER_POLICY(GainPolicy, GainPolicy::steiner_tree_for_graphs, SteinerTreeForGraphsTypes); -#endif -#endif + // ////////////////////////////////////////////////////////////////////////////// + // Gain Type Policies + // ////////////////////////////////////////////////////////////////////////////// + REGISTER_POLICY(GainPolicy, GainPolicy::km1, Km1GainTypes); + REGISTER_POLICY(GainPolicy, GainPolicy::cut, CutGainTypes); + #ifdef KAHYPAR_ENABLE_SOED_METRIC + REGISTER_POLICY(GainPolicy, GainPolicy::soed, SoedGainTypes); + #endif + #ifdef KAHYPAR_ENABLE_STEINER_TREE_METRIC + REGISTER_POLICY(GainPolicy, GainPolicy::steiner_tree, SteinerTreeGainTypes); + #endif + #ifdef KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES + REGISTER_POLICY(GainPolicy, GainPolicy::cut_for_graphs, CutGainForGraphsTypes); + #ifdef KAHYPAR_ENABLE_STEINER_TREE_METRIC + REGISTER_POLICY(GainPolicy, GainPolicy::steiner_tree_for_graphs, SteinerTreeForGraphsTypes); + #endif + #endif +} } // namespace mt_kahypar diff --git a/codestyle/fileheader.txt b/mt-kahypar/partition/registries/register_policies.h similarity index 89% rename from codestyle/fileheader.txt rename to mt-kahypar/partition/registries/register_policies.h index 7cab9a159..b7c68ce10 100644 --- a/codestyle/fileheader.txt +++ b/mt-kahypar/partition/registries/register_policies.h @@ -3,8 +3,7 @@ * * This file is part of Mt-KaHyPar. * - * Copyright (C) 2020 Lars Gottesbüren - * Copyright (C) 2020 Tobias Heuer + * Copyright (C) 2024 Nikolai Maas * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -25,3 +24,10 @@ * SOFTWARE. ******************************************************************************/ +#pragma once + +namespace mt_kahypar { + +void register_policies(); + +} // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_refinement_algorithms.cpp b/mt-kahypar/partition/registries/register_refinement_algorithms.cpp index 87eaa5e0e..bfdf4e810 100644 --- a/mt-kahypar/partition/registries/register_refinement_algorithms.cpp +++ b/mt-kahypar/partition/registries/register_refinement_algorithms.cpp @@ -25,6 +25,8 @@ * SOFTWARE. ******************************************************************************/ +#include "register_refinement_algorithms.h" + #include "kahypar-resources/meta/registrar.h" #include "kahypar-resources/meta/static_multi_dispatch_factory.h" #include "kahypar-resources/meta/typelist.h" @@ -96,7 +98,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< #define REGISTER_DISPATCHED_LP_REFINER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache, IRebalancer& rebalancer) { \ @@ -107,7 +109,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_LP_REFINER(id, refiner, t) \ - static kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ + kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache, IRebalancer& rebalancer) -> IRefiner* { \ @@ -115,7 +117,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_DISPATCHED_FM_REFINER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache, IRebalancer& rebalancer) { \ @@ -126,7 +128,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_FM_REFINER(id, refiner, t) \ - static kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ + kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache, IRebalancer& rebalancer) -> IRefiner* { \ @@ -134,7 +136,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_DISPATCHED_FM_STRATEGY(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const Context& context, FMSharedData& shared_data) { \ return dispatcher::create( \ @@ -144,7 +146,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_DISPATCHED_FLOW_SCHEDULER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache) { \ @@ -155,7 +157,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_FLOW_SCHEDULER(id, refiner, t) \ - static kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ + kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ id, \ [](const HypernodeID num_hypernodes, const HyperedgeID num_hyperedges, \ const Context& context, gain_cache_t gain_cache) -> IRefiner* { \ @@ -163,7 +165,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_DISPATCHED_REBALANCER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](HypernodeID num_hypernodes, const Context& context, gain_cache_t gain_cache) { \ return dispatcher::create( \ @@ -173,14 +175,14 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_REBALANCER(id, refiner, t) \ - static kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ + kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ id, \ [](HypernodeID num_hypernodes, const Context& context, gain_cache_t gain_cache) -> IRebalancer* { \ return new refiner(num_hypernodes, context, gain_cache); \ }) #define REGISTER_DISPATCHED_FLOW_REFINER(id, dispatcher, ...) \ - static kahypar::meta::Registrar register_ ## dispatcher( \ + kahypar::meta::Registrar register_ ## dispatcher( \ id, \ [](const HyperedgeID num_hyperedges, const Context& context) { \ return dispatcher::create( \ @@ -190,7 +192,7 @@ using FlowRefinementDispatcher = kahypar::meta::StaticMultiDispatchFactory< }) #define REGISTER_FLOW_REFINER(id, refiner, t) \ - static kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ + kahypar::meta::Registrar JOIN(register_ ## refiner, t)( \ id, \ [](const HyperedgeID num_Hyperedges, const Context& context) -> IFlowRefiner* { \ return new refiner(num_Hyperedges, context); \ @@ -212,44 +214,47 @@ kahypar::meta::PolicyBase& getGraphAndGainTypesPolicy(mt_kahypar_partition_type_ } -REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::label_propagation, - LabelPropagationDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::deterministic, - DeterministicLabelPropagationDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_LP_REFINER(LabelPropagationAlgorithm::do_nothing, DoNothingRefiner, 1); - -REGISTER_DISPATCHED_FM_REFINER(FMAlgorithm::kway_fm, - DefaultFMDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_DISPATCHED_FM_REFINER(FMAlgorithm::unconstrained_fm, - UnconstrainedFMDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_FM_REFINER(FMAlgorithm::do_nothing, DoNothingRefiner, 3); - -REGISTER_DISPATCHED_FM_STRATEGY(FMAlgorithm::kway_fm, - GainCacheFMStrategyDispatcher, +void register_refinement_algorithms() { + REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::label_propagation, + LabelPropagationDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_DISPATCHED_LP_REFINER(LabelPropagationAlgorithm::deterministic, + DeterministicLabelPropagationDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_LP_REFINER(LabelPropagationAlgorithm::do_nothing, DoNothingRefiner, 1); + + REGISTER_DISPATCHED_FM_REFINER(FMAlgorithm::kway_fm, + DefaultFMDispatcher, getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_DISPATCHED_FM_STRATEGY(FMAlgorithm::unconstrained_fm, - UnconstrainedFMStrategyDispatcher, + REGISTER_DISPATCHED_FM_REFINER(FMAlgorithm::unconstrained_fm, + UnconstrainedFMDispatcher, getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_FM_REFINER(FMAlgorithm::do_nothing, DoNothingRefiner, 3); + + REGISTER_DISPATCHED_FM_STRATEGY(FMAlgorithm::kway_fm, + GainCacheFMStrategyDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_DISPATCHED_FM_STRATEGY(FMAlgorithm::unconstrained_fm, + UnconstrainedFMStrategyDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + + REGISTER_DISPATCHED_FLOW_SCHEDULER(FlowAlgorithm::flow_cutter, + FlowSchedulerDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_FLOW_SCHEDULER(FlowAlgorithm::do_nothing, DoNothingRefiner, 4); + + REGISTER_DISPATCHED_REBALANCER(RebalancingAlgorithm::simple_rebalancer, + SimpleRebalancerDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_DISPATCHED_REBALANCER(RebalancingAlgorithm::advanced_rebalancer, + AdvancedRebalancerDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_REBALANCER(RebalancingAlgorithm::do_nothing, DoNothingRefiner, 5); + + REGISTER_DISPATCHED_FLOW_REFINER(FlowAlgorithm::flow_cutter, + FlowRefinementDispatcher, + getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); + REGISTER_FLOW_REFINER(FlowAlgorithm::do_nothing, DoNothingFlowRefiner, 6); +} -REGISTER_DISPATCHED_FLOW_SCHEDULER(FlowAlgorithm::flow_cutter, - FlowSchedulerDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_FLOW_SCHEDULER(FlowAlgorithm::do_nothing, DoNothingRefiner, 4); - -REGISTER_DISPATCHED_REBALANCER(RebalancingAlgorithm::simple_rebalancer, - SimpleRebalancerDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_DISPATCHED_REBALANCER(RebalancingAlgorithm::advanced_rebalancer, - AdvancedRebalancerDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_REBALANCER(RebalancingAlgorithm::do_nothing, DoNothingRefiner, 5); - -REGISTER_DISPATCHED_FLOW_REFINER(FlowAlgorithm::flow_cutter, - FlowRefinementDispatcher, - getGraphAndGainTypesPolicy(context.partition.partition_type, context.partition.gain_policy)); -REGISTER_FLOW_REFINER(FlowAlgorithm::do_nothing, DoNothingFlowRefiner, 6); } // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/register_refinement_algorithms.h b/mt-kahypar/partition/registries/register_refinement_algorithms.h new file mode 100644 index 000000000..5d939ce91 --- /dev/null +++ b/mt-kahypar/partition/registries/register_refinement_algorithms.h @@ -0,0 +1,33 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2024 Nikolai Maas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#pragma once + +namespace mt_kahypar { + +void register_refinement_algorithms(); + +} // namespace mt_kahypar diff --git a/mt-kahypar/partition/registries/registry.h b/mt-kahypar/partition/registries/registry.h new file mode 100644 index 000000000..50af10c18 --- /dev/null +++ b/mt-kahypar/partition/registries/registry.h @@ -0,0 +1,43 @@ +/******************************************************************************* + * MIT License + * + * This file is part of Mt-KaHyPar. + * + * Copyright (C) 2024 Nikolai Maas + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include "register_coarsening_algorithms.h" +#include "register_initial_partitioning_algorithms.h" +#include "register_policies.h" +#include "register_refinement_algorithms.h" + +namespace mt_kahypar { + +void register_algorithms_and_policies() { + register_coarsening_algorithms(); + register_initial_partitioning_algorithms(); + register_refinement_algorithms(); + register_policies(); +} + +} // namespace mt_kahypar diff --git a/mt-kahypar/utils/CMakeLists.txt b/mt-kahypar/utils/CMakeLists.txt index ad4fe7407..e54749d8e 100644 --- a/mt-kahypar/utils/CMakeLists.txt +++ b/mt-kahypar/utils/CMakeLists.txt @@ -2,10 +2,5 @@ set(UtilSources memory_tree.cpp ) -foreach(modtarget IN LISTS PARTITIONING_SUITE_TARGETS) - target_sources(${modtarget} PRIVATE ${UtilSources}) -endforeach() - -foreach(modtarget IN LISTS TOOLS_TARGETS) - target_sources(${modtarget} PRIVATE ${UtilSources}) -endforeach() \ No newline at end of file +target_sources(MtKaHyPar-Sources INTERFACE ${UtilSources}) +target_sources(MtKaHyPar-ToolsSources INTERFACE ${UtilSources}) diff --git a/mt-kahypar/utils/cast.h b/mt-kahypar/utils/cast.h index c5f0574a3..e006cf8f9 100644 --- a/mt-kahypar/utils/cast.h +++ b/mt-kahypar/utils/cast.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/utils/exception.h" diff --git a/mt-kahypar/utils/delete.h b/mt-kahypar/utils/delete.h index f17233107..5a2c90ef5 100644 --- a/mt-kahypar/utils/delete.h +++ b/mt-kahypar/utils/delete.h @@ -28,7 +28,7 @@ #include -#include "include/libmtkahypartypes.h" +#include "include/mtkahypartypes.h" #include "mt-kahypar/definitions.h" #include "mt-kahypar/macros.h" @@ -38,11 +38,12 @@ namespace mt_kahypar::utils { void delete_hypergraph(mt_kahypar_hypergraph_t hg) { if ( hg.hypergraph ) { switch ( hg.type ) { - case STATIC_GRAPH: delete reinterpret_cast(hg.hypergraph); break; - case DYNAMIC_GRAPH: delete reinterpret_cast(hg.hypergraph); break; case STATIC_HYPERGRAPH: delete reinterpret_cast(hg.hypergraph); break; - case DYNAMIC_HYPERGRAPH: delete reinterpret_cast(hg.hypergraph); break; - case NULLPTR_HYPERGRAPH: break; + ENABLE_GRAPHS(case STATIC_GRAPH: delete reinterpret_cast(hg.hypergraph); break;) + ENABLE_HIGHEST_QUALITY(case DYNAMIC_HYPERGRAPH: delete reinterpret_cast(hg.hypergraph); break;) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case DYNAMIC_GRAPH: delete reinterpret_cast(hg.hypergraph); break;) + case NULLPTR_HYPERGRAPH: + default: break; } } } @@ -50,12 +51,13 @@ void delete_hypergraph(mt_kahypar_hypergraph_t hg) { void delete_partitioned_hypergraph(mt_kahypar_partitioned_hypergraph_t phg) { if ( phg.partitioned_hg ) { switch ( phg.type ) { - case MULTILEVEL_GRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break; - case N_LEVEL_GRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break; case MULTILEVEL_HYPERGRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break; - case LARGE_K_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break; - case N_LEVEL_HYPERGRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break; + ENABLE_GRAPHS(case MULTILEVEL_GRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break;) + ENABLE_LARGE_K(case LARGE_K_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break;) + ENABLE_HIGHEST_QUALITY(case N_LEVEL_HYPERGRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break;) + ENABLE_HIGHEST_QUALITY_FOR_GRAPHS(case N_LEVEL_GRAPH_PARTITIONING: delete reinterpret_cast(phg.partitioned_hg); break;) case NULLPTR_PARTITION: break; + default: break; } } } diff --git a/mt-kahypar/utils/progress_bar.h b/mt-kahypar/utils/progress_bar.h index 8395ea64a..dbb591be8 100644 --- a/mt-kahypar/utils/progress_bar.h +++ b/mt-kahypar/utils/progress_bar.h @@ -32,10 +32,10 @@ #include #include #include -#if defined(__linux__) or defined(__APPLE__) -#include -#elif _WIN32 +#if _WIN32 #include +#else +#include #endif #include #include @@ -60,14 +60,14 @@ class ProgressBar { _objective(objective), _progress_bar_size(0), _enable(enable) { - #if defined(__linux__) or defined(__APPLE__) - struct winsize w; - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - _progress_bar_size = w.ws_col / 2; - #elif _WIN32 + #if _WIN32 CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); _progress_bar_size = (csbi.srWindow.Right - csbi.srWindow.Left + 1)/2; + #else + struct winsize w; + ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); + _progress_bar_size = w.ws_col / 2; #endif display_progress(); } diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 3e7279bef..97a2bf031 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -1,33 +1,13 @@ -################################################################################ -# python/CMakeLists.txt -# -# Copyright (c) 2019 Timo Bingmann -# -# All rights reserved. Published under the MIT License in the LICENSE file. -################################################################################ - -add_subdirectory(pybind11) -include_directories(${PROJECT_SOURCE_DIR}) +FetchContent_Declare( + pybind11 SYSTEM EXCLUDE_FROM_ALL + GIT_REPOSITORY https://github.com/pybind/pybind11.git + GIT_TAG ${KAHYPAR_PYBIND11_VERSION} +) +FetchContent_MakeAvailable(pybind11) pybind11_add_module(mtkahypar_python module.cpp) -target_link_libraries(mtkahypar_python PRIVATE TBB::tbb TBB::tbbmalloc_proxy) - -if(KAHYPAR_DOWNLOAD_BOOST) - target_link_libraries(mtkahypar_python PRIVATE mini_boost) -elseif(NOT MT_KAHYPAR_DISABLE_BOOST) - target_link_libraries(mtkahypar_python PRIVATE Boost::program_options) -endif() - -SET_TARGET_PROPERTIES(mtkahypar_python PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") -target_compile_definitions(mtkahypar_python PUBLIC MT_KAHYPAR_LIBRARY_MODE) -target_compile_definitions(mtkahypar_python PUBLIC KAHYPAR_ENABLE_LARGE_K_PARTITIONING_FEATURES) -target_compile_definitions(mtkahypar_python PUBLIC KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES) -target_compile_definitions(mtkahypar_python PUBLIC KAHYPAR_ENABLE_SOED_METRIC) -target_compile_definitions(mtkahypar_python PUBLIC KAHYPAR_ENABLE_STEINER_TREE_METRIC) - -set(PARTITIONING_SUITE_TARGETS ${PARTITIONING_SUITE_TARGETS} mtkahypar_python PARENT_SCOPE) +target_link_libraries(mtkahypar_python PRIVATE MtKaHyPar-LibraryBuildSources) +set_target_properties(mtkahypar_python PROPERTIES COMPILE_FLAGS "-fvisibility=hidden") # rename mtkahypar_python target output to mtkahypar set_target_properties(mtkahypar_python PROPERTIES OUTPUT_NAME mtkahypar) - -################################################################################ diff --git a/python/examples/improve_partition.py b/python/examples/improve_partition.py index 0e37ffc0b..f15c93a39 100644 --- a/python/examples/improve_partition.py +++ b/python/examples/improve_partition.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/map_hypergraph_onto_target_graph.py b/python/examples/map_hypergraph_onto_target_graph.py index 144c711a5..40f5bf150 100644 --- a/python/examples/map_hypergraph_onto_target_graph.py +++ b/python/examples/map_hypergraph_onto_target_graph.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/partition_graph.py b/python/examples/partition_graph.py index cdfb1e3d2..db38e25e9 100644 --- a/python/examples/partition_graph.py +++ b/python/examples/partition_graph.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/partition_hypergraph.py b/python/examples/partition_hypergraph.py index e3bad4d2b..34acebaad 100644 --- a/python/examples/partition_hypergraph.py +++ b/python/examples/partition_hypergraph.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/partition_hypergraph_into_large_k.py b/python/examples/partition_hypergraph_into_large_k.py index 6e759639c..7bfeb0803 100644 --- a/python/examples/partition_hypergraph_into_large_k.py +++ b/python/examples/partition_hypergraph_into_large_k.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/partition_with_fixed_vertices.py b/python/examples/partition_with_fixed_vertices.py index b59d49dec..dd39b03b4 100644 --- a/python/examples/partition_with_fixed_vertices.py +++ b/python/examples/partition_with_fixed_vertices.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/examples/partition_with_individual_block_weights.py b/python/examples/partition_with_individual_block_weights.py index 13874412f..71e579bb9 100644 --- a/python/examples/partition_with_individual_block_weights.py +++ b/python/examples/partition_with_individual_block_weights.py @@ -8,7 +8,7 @@ mydir = os.path.dirname(os.path.realpath(__file__)) # Initialize thread pool -mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) # use all available cores +mtkahypar.initialize(multiprocessing.cpu_count()) # use all available cores # Setup partitioning context context = mtkahypar.Context() diff --git a/python/module.cpp b/python/module.cpp index cd3e19963..c642f0af5 100644 --- a/python/module.cpp +++ b/python/module.cpp @@ -34,7 +34,11 @@ #include #include -#include "include/libmtkahypartypes.h" +#ifndef KAHYPAR_DISABLE_HWLOC + #include +#endif + +#include "include/mtkahypartypes.h" #include "include/helper_functions.h" #include "mt-kahypar/definitions.h" @@ -43,37 +47,43 @@ #include "mt-kahypar/partition/metrics.h" #include "mt-kahypar/partition/partitioner.h" #include "mt-kahypar/partition/mapping/target_graph.h" +#include "mt-kahypar/partition/registries/registry.h" #include "mt-kahypar/io/hypergraph_factory.h" #include "mt-kahypar/io/hypergraph_io.h" #include "mt-kahypar/io/presets.h" #include "mt-kahypar/utils/cast.h" #include "mt-kahypar/utils/randomize.h" - -#ifndef MT_KAHYPAR_DISABLE_BOOST #include "mt-kahypar/io/command_line_options.h" -#endif + namespace py = pybind11; using namespace mt_kahypar; namespace { - void initialize_thread_pool(const size_t num_threads) { + void initialize(const size_t num_threads) { size_t P = num_threads; - size_t num_available_cpus = mt_kahypar::HardwareTopology::instance().num_cpus(); - if ( num_available_cpus < num_threads ) { - WARNING("There are currently only" << num_available_cpus << "cpus available." - << "Setting number of threads from" << num_threads - << "to" << num_available_cpus); - P = num_available_cpus; - } + #ifndef KAHYPAR_DISABLE_HWLOC + size_t num_available_cpus = mt_kahypar::HardwareTopology::instance().num_cpus(); + if ( num_available_cpus < num_threads ) { + WARNING("There are currently only" << num_available_cpus << "cpus available." + << "Setting number of threads from" << num_threads + << "to" << num_available_cpus); + P = num_available_cpus; + } + #endif // Initialize TBB task arenas on numa nodes mt_kahypar::TBBInitializer::instance(P); - // We set the membind policy to interleaved allocations in order to - // distribute allocations evenly across NUMA nodes - hwloc_cpuset_t cpuset = mt_kahypar::TBBInitializer::instance().used_cpuset(); - mt_kahypar::parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); - hwloc_bitmap_free(cpuset); + + #ifndef KAHYPAR_DISABLE_HWLOC + // We set the membind policy to interleaved allocations in order to + // distribute allocations evenly across NUMA nodes + hwloc_cpuset_t cpuset = mt_kahypar::TBBInitializer::instance().used_cpuset(); + mt_kahypar::parallel::HardwareTopology<>::instance().activate_interleaved_membind_policy(cpuset); + hwloc_bitmap_free(cpuset); + #endif + + register_algorithms_and_policies(); } template @@ -230,8 +240,8 @@ PYBIND11_MODULE(mtkahypar, m) { // ####################### Initialize Thread Pool ####################### - m.def("initializeThreadPool", &initialize_thread_pool, - "Initializes the thread pool with the given number of threads", + m.def("initialize", &initialize, + "General initialization. Initializes the thread pool with the given number of threads", py::arg("number of threads")); // ####################### Initialize Random Number Generator ####################### @@ -254,12 +264,10 @@ PYBIND11_MODULE(mtkahypar, m) { } }, "Loads a preset for partitioning (DETERMINISTIC, LARGE_K, DEFAULT or QUALITY)", py::arg("preset type")) -#ifndef MT_KAHYPAR_DISABLE_BOOST .def("loadConfigurationFile", [](Context& context, const std::string& config_file) { mt_kahypar::parseIniToContext(context, config_file); }, "Read partitioning configuration from file", py::arg("configuration file")) -#endif .def("setPartitioningParameters", [](Context& context, const PartitionID k, diff --git a/python/pybind11 b/python/pybind11 deleted file mode 160000 index 7c33cdc2d..000000000 --- a/python/pybind11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7c33cdc2d39c7b99a122579f53bc94c8eb3332ff diff --git a/python/tests/test_mtkahypar.py b/python/tests/test_mtkahypar.py index 0d9163e78..bd99d6b69 100644 --- a/python/tests/test_mtkahypar.py +++ b/python/tests/test_mtkahypar.py @@ -37,7 +37,7 @@ class MainTest(unittest.TestCase): def setUp(self): - mtkahypar.initializeThreadPool(multiprocessing.cpu_count()) + mtkahypar.initialize(multiprocessing.cpu_count()) def test_set_partitioning_parameters_in_context(self): context = mtkahypar.Context() diff --git a/scripts/checkout_submodules.sh b/scripts/checkout_submodules.sh deleted file mode 100755 index 645702022..000000000 --- a/scripts/checkout_submodules.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash -source scripts/submodule_heads.sh -ROOT=${PWD} - -# Initialize GOOGLETEST -[ ! "$(ls -A external_tools/googletest)" ] && -git clone https://github.com/google/googletest.git external_tools/googletest && -cd external_tools/googletest && git checkout ${GOOGLETEST_HEAD} && cd ${ROOT} - -# Initialize WHFC -[ ! "$(ls -A external_tools/WHFC)" ] && -git clone https://github.com/larsgottesbueren/WHFC.git external_tools/WHFC && -cd external_tools/WHFC && git checkout ${WHFC_HEAD} && cd ${ROOT} - -# Initialize PYBIND11 -[ ! "$(ls -A python/pybind11)" ] && -git clone https://github.com/pybind/pybind11.git python/pybind11 && -cd python/pybind11 && git checkout ${PYBIND11_HEAD} && cd ${ROOT} - -# Initialize GROWT -[ ! "$(ls -A external_tools/growt)" ] && -git clone --depth=1 --recursive https://github.com/TooBiased/growt.git external_tools/growt && -cd external_tools/growt && git checkout ${GROWT_HEAD} && cd ${ROOT} - -# Initialize KAHYPAR-SHARED-RESOURCES -[ ! "$(ls -A external_tools/kahypar-shared-resources)" ] && -git clone https://github.com/kahypar/kahypar-shared-resources.git external_tools/kahypar-shared-resources && -cd external_tools/kahypar-shared-resources && git checkout ${KAHYPAR_SHARED_RESOURCES_HEAD} && cd ${ROOT} diff --git a/scripts/download_boost.cmake b/scripts/download_boost.cmake deleted file mode 100644 index 3de65d318..000000000 --- a/scripts/download_boost.cmake +++ /dev/null @@ -1,7 +0,0 @@ -include(FetchContent) -FetchContent_Populate( - boost-src - URL http://downloads.sourceforge.net/project/boost/boost/1.69.0/boost_1_69_0.tar.bz2 - URL_HASH MD5=a1332494397bf48332cb152abfefcec2 - SOURCE_DIR external_tools/boost -) diff --git a/scripts/download_tbb_linux.cmake b/scripts/download_tbb_linux.cmake deleted file mode 100644 index 02fdb05eb..000000000 --- a/scripts/download_tbb_linux.cmake +++ /dev/null @@ -1,7 +0,0 @@ -include(FetchContent) -FetchContent_Populate( - tbb - URL https://github.com/oneapi-src/oneTBB/releases/download/v2021.7.0/oneapi-tbb-2021.7.0-lin.tgz - URL_HASH SHA256=3c2b3287c595e2bb833c025fcd271783963b7dfae8dc681440ea6afe5d550e6a - SOURCE_DIR external_tools/tbb -) \ No newline at end of file diff --git a/scripts/download_tbb_windows.cmake b/scripts/download_tbb_windows.cmake deleted file mode 100644 index c0814c148..000000000 --- a/scripts/download_tbb_windows.cmake +++ /dev/null @@ -1,7 +0,0 @@ -include(FetchContent) -FetchContent_Populate( - tbb - URL https://github.com/oneapi-src/oneTBB/releases/download/v2021.8.0/oneapi-tbb-2021.8.0-win.zip - URL_HASH SHA256=b9265d4dc5b74e27176c6a6b696882935f605191d014a62c010c9610904e7f65 - SOURCE_DIR external_tools/tbb -) \ No newline at end of file diff --git a/scripts/generate_submodule_checkout_scripts.sh b/scripts/generate_submodule_checkout_scripts.sh deleted file mode 100755 index 7cff4a3ea..000000000 --- a/scripts/generate_submodule_checkout_scripts.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -SUBMODULE_FILE=".gitmodules" - -IFS=$'\n' -submodule_dirs=( $(grep path $SUBMODULE_FILE | cut -d'=' -f2 | cut -d' ' -f2) ) -module_names=( $(grep path $SUBMODULE_FILE | cut -d'=' -f2 | cut -d' ' -f2 | cut -d"/" -f2 | awk '{print toupper($0)}') ) -git_repos=( $(grep url $SUBMODULE_FILE | cut -d'=' -f2 | cut -d' ' -f2) ) - -# Generate script exporting commit hashes of submodules as environment variable -echo "#!/bin/bash" > scripts/submodule_heads.sh -for i in "${!submodule_dirs[@]}"; do - echo "export ${module_names[$i]}_HEAD=\"$(cat .git/modules/${submodule_dirs[$i]}/HEAD)\"" >> scripts/submodule_heads.sh -done - -# Generate script that checkouts submodules -echo "#!/bin/bash" > scripts/checkout_submodules.sh -echo "source scripts/submodule_heads.sh" >> scripts/checkout_submodules.sh -echo "ROOT=\${PWD}" >> scripts/checkout_submodules.sh -for i in "${!submodule_dirs[@]}"; do - echo "" >> scripts/checkout_submodules.sh - echo "# Initialize ${module_names[$i]}" >> scripts/checkout_submodules.sh - echo "[ ! \"\$(ls -A ${submodule_dirs[$i]})\" ] &&" >> scripts/checkout_submodules.sh - echo "git clone ${git_repos[$i]} ${submodule_dirs[$i]} &&" >> scripts/checkout_submodules.sh - echo "cd ${submodule_dirs[$i]} && git checkout \${${module_names[$i]}_HEAD} && cd \${ROOT}" >> scripts/checkout_submodules.sh -done - -chmod u+x scripts/submodule_heads.sh -chmod u+x scripts/checkout_submodules.sh - - - diff --git a/scripts/submodule_heads.sh b/scripts/submodule_heads.sh deleted file mode 100755 index 30ee07933..000000000 --- a/scripts/submodule_heads.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -export GOOGLETEST_HEAD="53495a2a7d6ba7e0691a7f3602e9a5324bba6e45" -export WHFC_HEAD="21d99e1dbb3820d7222bcd69332cfad05cc56d17" -export PYBIND11_HEAD="ee2b5226295d67b690faddd446a329bb2840a1a8" -export GROWT_HEAD="0c1148ebcdfd4c04803be79706533ad09cc81d37" -export KAHYPAR_SHARED_RESOURCES_HEAD="b46e1be22644310b707734cc0ec3672a17a99751" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2c1576c0c..28221950d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,16 +1,11 @@ -add_executable(mt_kahypar_tests run_tests.cpp) -target_link_libraries(mt_kahypar_tests gtest gtest_main ${CMAKE_THREAD_LIBS_INIT}) -set_property(TARGET mt_kahypar_tests PROPERTY CXX_STANDARD 17) -set_property(TARGET mt_kahypar_tests PROPERTY CXX_STANDARD_REQUIRED ON) -target_link_libraries(mt_kahypar_tests ${Boost_LIBRARIES} TBB::tbb TBB::tbbmalloc_proxy) +add_executable(mtkahypar_tests run_tests.cpp) +target_link_libraries(mtkahypar_tests MtKaHyPar-BuildSources MtKaHyPar-Test) # suppress warnings generated by TYPED_TEST_SUITE macro from gtest -target_compile_options(mt_kahypar_tests PRIVATE "-Wno-gnu-zero-variadic-macro-arguments") +target_compile_options(mtkahypar_tests PRIVATE "-Wno-gnu-zero-variadic-macro-arguments") add_subdirectory(datastructures) add_subdirectory(interface) add_subdirectory(io) add_subdirectory(parallel) add_subdirectory(partition) - -set(PARTITIONING_SUITE_TARGETS ${PARTITIONING_SUITE_TARGETS} mt_kahypar_tests PARENT_SCOPE) diff --git a/tests/datastructures/CMakeLists.txt b/tests/datastructures/CMakeLists.txt index 3435337fe..aa4635fd1 100644 --- a/tests/datastructures/CMakeLists.txt +++ b/tests/datastructures/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE static_hypergraph_test.cc partitioned_hypergraph_test.cc delta_partitioned_hypergraph_test.cc @@ -14,14 +14,14 @@ target_sources(mt_kahypar_tests PRIVATE fixed_vertex_support_test.cc) if ( KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES ) - target_sources(mt_kahypar_tests PRIVATE + target_sources(mtkahypar_tests PRIVATE static_graph_test.cc partitioned_graph_test.cc delta_partitioned_graph_test.cc) endif() if ( KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES ) - target_sources(mt_kahypar_tests PRIVATE + target_sources(mtkahypar_tests PRIVATE dynamic_hypergraph_test.cc dynamic_partitioned_hypergraph_test.cc contraction_tree_test.cc @@ -29,7 +29,7 @@ if ( KAHYPAR_ENABLE_HIGHEST_QUALITY_FEATURES ) nlevel_smoke_test.cc) if ( KAHYPAR_ENABLE_GRAPH_PARTITIONING_FEATURES ) - target_sources(mt_kahypar_tests PRIVATE + target_sources(mtkahypar_tests PRIVATE dynamic_adjacency_array_test.cc dynamic_graph_test.cc nlevel_smoke_test.cc) diff --git a/tests/datastructures/array_test.cc b/tests/datastructures/array_test.cc index a548c3f5c..520224af6 100644 --- a/tests/datastructures/array_test.cc +++ b/tests/datastructures/array_test.cc @@ -31,19 +31,12 @@ #include "mt-kahypar/parallel/stl/scalable_vector.h" #include "mt-kahypar/datastructures/array.h" -#include "mt-kahypar/parallel/hardware_topology.h" -#include "mt-kahypar/parallel/tbb_initializer.h" -#include "tests/parallel/topology_mock.h" using ::testing::Test; namespace mt_kahypar { namespace ds { -using TopoMock = mt_kahypar::parallel::TopologyMock<2>; -using HwTopology = mt_kahypar::parallel::HardwareTopology; -using TBB = mt_kahypar::parallel::TBBInitializer; - TEST(AArray, WritesAnValueToStrippedVector1) { Array vec(256, 0); vec[0] = 31; diff --git a/tests/datastructures/hypergraph_fixtures.h b/tests/datastructures/hypergraph_fixtures.h index cfc8e6cfb..d77791870 100644 --- a/tests/datastructures/hypergraph_fixtures.h +++ b/tests/datastructures/hypergraph_fixtures.h @@ -29,15 +29,26 @@ #include "gmock/gmock.h" #include "mt-kahypar/definitions.h" -#include "mt-kahypar/parallel/hardware_topology.h" #include "mt-kahypar/parallel/tbb_initializer.h" -#include "tests/parallel/topology_mock.h" + +#ifndef KAHYPAR_DISABLE_HWLOC + #include "mt-kahypar/parallel/hardware_topology.h" + #include "tests/parallel/topology_mock.h" +#endif using ::testing::Test; namespace mt_kahypar { namespace ds { +#ifndef KAHYPAR_DISABLE_HWLOC + using TopoMock = mt_kahypar::parallel::TopologyMock<2>; + using HwTopology = mt_kahypar::parallel::HardwareTopology; + using TBB = mt_kahypar::parallel::TBBInitializer; +#else + using TBB = mt_kahypar::parallel::SimpleTBBInitializer; +#endif + static auto identity = [](const HypernodeID& id) { return id; }; template diff --git a/tests/interface/CMakeLists.txt b/tests/interface/CMakeLists.txt index c06ff455e..592d16ba5 100644 --- a/tests/interface/CMakeLists.txt +++ b/tests/interface/CMakeLists.txt @@ -1,4 +1,4 @@ file(COPY test_instances DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -add_gmock_test(interface_test interface_test.cc) -target_link_libraries(interface_test ${Boost_LIBRARIES} mtkahypar) +add_gmock_test(mtkahypar_interface_test interface_test.cc) +target_link_libraries(mtkahypar_interface_test MtKaHyPar-LibraryBuildSources MtKaHyPar-Test mtkahypar) diff --git a/tests/interface/interface_test.cc b/tests/interface/interface_test.cc index b7db49d97..7747dddcb 100644 --- a/tests/interface/interface_test.cc +++ b/tests/interface/interface_test.cc @@ -31,7 +31,7 @@ #include -#include "libmtkahypar.h" +#include "mtkahypar.h" #include "mt-kahypar/macros.h" #include "mt-kahypar/partition/context.h" #include "mt-kahypar/io/hypergraph_io.h" @@ -498,7 +498,7 @@ namespace mt_kahypar { } void SetUp() { - mt_kahypar_initialize_thread_pool(std::thread::hardware_concurrency(), false); + mt_kahypar_initialize(std::thread::hardware_concurrency(), false); context = mt_kahypar_context_new(); target_graph = mt_kahypar_read_target_graph_from_file(TARGET_GRAPH_FILE); } diff --git a/tests/io/CMakeLists.txt b/tests/io/CMakeLists.txt index 4da2a72fd..44da4ef4d 100644 --- a/tests/io/CMakeLists.txt +++ b/tests/io/CMakeLists.txt @@ -1,9 +1,7 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE hypergraph_io_test.cc sql_plottools_serializer_test.cc ) -if(NOT MT_KAHYPAR_DISABLE_BOOST) - configure_file(context_test.cc.in ${PROJECT_BINARY_DIR}/tests/io/context_test.cc) - target_sources(mt_kahypar_tests PRIVATE ${PROJECT_BINARY_DIR}/tests/io/context_test.cc) -endif() +configure_file(context_test.cc.in ${PROJECT_BINARY_DIR}/tests/io/context_test.cc) +target_sources(mtkahypar_tests PRIVATE ${PROJECT_BINARY_DIR}/tests/io/context_test.cc) diff --git a/tests/parallel/CMakeLists.txt b/tests/parallel/CMakeLists.txt index 150d1811a..73f41ba7a 100644 --- a/tests/parallel/CMakeLists.txt +++ b/tests/parallel/CMakeLists.txt @@ -1,4 +1,4 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE work_container_test.cc memory_pool_test.cc prefix_sum_test.cc diff --git a/tests/parallel/memory_pool_test.cc b/tests/parallel/memory_pool_test.cc index 6f5eec1c2..1a47ba86f 100644 --- a/tests/parallel/memory_pool_test.cc +++ b/tests/parallel/memory_pool_test.cc @@ -30,20 +30,12 @@ #include #include "mt-kahypar/parallel/memory_pool.h" -#include "mt-kahypar/parallel/hardware_topology.h" -#include "mt-kahypar/parallel/tbb_initializer.h" -#include "tests/parallel/topology_mock.h" using ::testing::Test; namespace mt_kahypar { namespace parallel { -using TopoMock = mt_kahypar::parallel::TopologyMock<2>; -using HwTopology = mt_kahypar::parallel::HardwareTopology; -using TBB = mt_kahypar::parallel::TBBInitializer; - - template void executeConcurrent(F f1, K f2) { std::atomic cnt(0); diff --git a/tests/parallel/work_container_test.cc b/tests/parallel/work_container_test.cc index d685181d4..6b3af9e0a 100644 --- a/tests/parallel/work_container_test.cc +++ b/tests/parallel/work_container_test.cc @@ -26,9 +26,12 @@ #include "gmock/gmock.h" -#include #include +#include + +#include "mt-kahypar/parallel/work_stack.h" + using ::testing::Test; namespace mt_kahypar { diff --git a/tests/partition/coarsening/CMakeLists.txt b/tests/partition/coarsening/CMakeLists.txt index e19c6c5a8..a3d0b446e 100644 --- a/tests/partition/coarsening/CMakeLists.txt +++ b/tests/partition/coarsening/CMakeLists.txt @@ -1,2 +1,2 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE coarsener_test.cc) diff --git a/tests/partition/determinism/CMakeLists.txt b/tests/partition/determinism/CMakeLists.txt index 796b0b084..06c121549 100644 --- a/tests/partition/determinism/CMakeLists.txt +++ b/tests/partition/determinism/CMakeLists.txt @@ -1,3 +1,3 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE determinism_test.cc ) diff --git a/tests/partition/initial_partitioning/CMakeLists.txt b/tests/partition/initial_partitioning/CMakeLists.txt index 143da9a60..2944a7310 100644 --- a/tests/partition/initial_partitioning/CMakeLists.txt +++ b/tests/partition/initial_partitioning/CMakeLists.txt @@ -1,9 +1,10 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE flat_initial_partitioner_test.cc initial_partitioning_data_container_test.cc - pool_initial_partitioner_test.cc ) -if(NOT MT_KAHYPAR_DISABLE_BOOST) - target_sources(mt_kahypar_tests PRIVATE initial_partitioner_test.cc) +if(NOT KAHYPAR_DISABLE_HWLOC) + target_sources(mtkahypar_tests PRIVATE + initial_partitioner_test.cc + pool_initial_partitioner_test.cc) endif() diff --git a/tests/partition/mapping/CMakeLists.txt b/tests/partition/mapping/CMakeLists.txt index 9bff26328..d44ae50e8 100644 --- a/tests/partition/mapping/CMakeLists.txt +++ b/tests/partition/mapping/CMakeLists.txt @@ -1,5 +1,5 @@ if ( KAHYPAR_ENABLE_STEINER_TREE_METRIC ) - target_sources(mt_kahypar_tests PRIVATE + target_sources(mtkahypar_tests PRIVATE target_graph_test.cc set_enumerator_test.cc ) diff --git a/tests/partition/preprocessing/CMakeLists.txt b/tests/partition/preprocessing/CMakeLists.txt index 6f31b5db2..916b7f22d 100644 --- a/tests/partition/preprocessing/CMakeLists.txt +++ b/tests/partition/preprocessing/CMakeLists.txt @@ -1,3 +1,3 @@ -target_sources(mt_kahypar_tests PRIVATE +target_sources(mtkahypar_tests PRIVATE louvain_test.cc ) diff --git a/tests/partition/refinement/CMakeLists.txt b/tests/partition/refinement/CMakeLists.txt index fd4b6aa1f..47be31378 100644 --- a/tests/partition/refinement/CMakeLists.txt +++ b/tests/partition/refinement/CMakeLists.txt @@ -1,11 +1,10 @@ -target_sources(mt_kahypar_tests PRIVATE - bipartitioning_gain_policy_test.cc +target_sources(mtkahypar_tests PRIVATE refinement_adapter_test.cc problem_construction_test.cc scheduler_test.cc # quotient_graph_test.cc gain_policy_test.cc - label_propagation_refiner_test.cc + bipartitioning_gain_policy_test.cc rollback_test.cc rebalance_test.cc advanced_rebalancer_test.cc @@ -15,3 +14,7 @@ target_sources(mt_kahypar_tests PRIVATE fm_strategy_test.cc flow_construction_test.cc ) + +if(NOT KAHYPAR_DISABLE_HWLOC) + target_sources(mtkahypar_tests PRIVATE label_propagation_refiner_test.cc) +endif() diff --git a/tests/run_tests.cpp b/tests/run_tests.cpp index 5a230da67..f45944f5f 100644 --- a/tests/run_tests.cpp +++ b/tests/run_tests.cpp @@ -2,13 +2,15 @@ #include #include "mt-kahypar/definitions.h" +#include "mt-kahypar/partition/registries/registry.h" int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); + mt_kahypar::register_algorithms_and_policies(); mt_kahypar::TBBInitializer::instance(std::thread::hardware_concurrency()); const int result = RUN_ALL_TESTS(); mt_kahypar::TBBInitializer::instance().terminate(); return result; -} \ No newline at end of file +} diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 2acfeda2e..00aa21ea3 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,119 +1,71 @@ -add_executable(SnapGraphToHgr snap_graph_to_hgr.cc) -target_link_libraries(SnapGraphToHgr ${Boost_LIBRARIES}) -target_link_libraries(SnapGraphToHgr TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET SnapGraphToHgr PROPERTY CXX_STANDARD 17) -set_property(TARGET SnapGraphToHgr PROPERTY CXX_STANDARD_REQUIRED ON) +################################################################# +## Minimal tools with single source file ## +################################################################# + +# meta target for single executable tools +add_library(MtKaHyPar-ToolsMin INTERFACE) +target_link_libraries(MtKaHyPar-ToolsMin INTERFACE MtKaHyPar-Include MtKaHyPar-BuildFlags) + +add_executable(SnapToHgr snap_to_hgr.cc) +target_link_libraries(SnapToHgr MtKaHyPar-ToolsMin) + +add_executable(SnapToMetis snap_to_metis.cc) +target_link_libraries(SnapToMetis MtKaHyPar-ToolsMin) + +add_executable(BenchShuffle bench_deterministic_shuffling.cc) +target_link_libraries(BenchShuffle MtKaHyPar-ToolsMin) + +add_executable(MtxToGraph mtx_to_graph.cc) +target_link_libraries(MtxToGraph MtKaHyPar-BuildFlags) + + +################################################################# +## Tools with more dependencies ## +################################################################# + +# meta target for tools with more dependencies +add_library(MtKaHyPar-BuildTools OBJECT "") +target_link_libraries(MtKaHyPar-BuildTools PRIVATE MtKaHyPar-ToolsSources) +target_link_libraries(MtKaHyPar-BuildTools PUBLIC MtKaHyPar-Include MtKaHyPar-BuildFlags) add_executable(GraphToHgr graph_to_hgr.cc) -target_link_libraries(GraphToHgr ${Boost_LIBRARIES}) -target_link_libraries(GraphToHgr TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET GraphToHgr PROPERTY CXX_STANDARD 17) -set_property(TARGET GraphToHgr PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(GraphToHgr MtKaHyPar-BuildTools) add_executable(HgrToGraph hgr_to_graph.cc) -target_link_libraries(HgrToGraph ${Boost_LIBRARIES}) -target_link_libraries(HgrToGraph TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET HgrToGraph PROPERTY CXX_STANDARD 17) -set_property(TARGET HgrToGraph PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(HgrToParkway hgr_to_parkway_converter.cc) -target_link_libraries(HgrToParkway ${Boost_LIBRARIES}) -target_link_libraries(HgrToParkway TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET HgrToParkway PROPERTY CXX_STANDARD 17) -set_property(TARGET HgrToParkway PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(HgrToZoltan hgr_to_zoltan_converter.cc) -target_link_libraries(HgrToZoltan ${Boost_LIBRARIES}) -target_link_libraries(HgrToZoltan TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET HgrToZoltan PROPERTY CXX_STANDARD 17) -set_property(TARGET HgrToZoltan PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(HgrToGraph MtKaHyPar-BuildTools) -add_executable(HypergraphStats hypergraph_stats.cc) -target_link_libraries(HypergraphStats ${Boost_LIBRARIES}) -target_link_libraries(HypergraphStats TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET HypergraphStats PROPERTY CXX_STANDARD 17) -set_property(TARGET HypergraphStats PROPERTY CXX_STANDARD_REQUIRED ON) +add_executable(HgrToParkway hgr_to_parkway.cc) +target_link_libraries(HgrToParkway MtKaHyPar-BuildTools) + +add_executable(HgrToZoltan hgr_to_zoltan.cc) +target_link_libraries(HgrToZoltan MtKaHyPar-BuildTools) -add_executable(MetisToScotch metis_to_scotch_converter.cc) -target_link_libraries(MetisToScotch ${Boost_LIBRARIES}) -target_link_libraries(MetisToScotch TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET MetisToScotch PROPERTY CXX_STANDARD 17) -set_property(TARGET MetisToScotch PROPERTY CXX_STANDARD_REQUIRED ON) +add_executable(MetisToScotch metis_to_scotch.cc) +target_link_libraries(MetisToScotch MtKaHyPar-BuildTools) + +add_executable(HypergraphStats hypergraph_stats.cc) +target_link_libraries(HypergraphStats MtKaHyPar-BuildTools) add_executable(OneToOneMapping one_to_one_mapping.cc) -target_link_libraries(OneToOneMapping ${Boost_LIBRARIES}) -target_link_libraries(OneToOneMapping TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET OneToOneMapping PROPERTY CXX_STANDARD 17) -set_property(TARGET OneToOneMapping PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(OneToOneMapping MtKaHyPar-BuildTools) -add_executable(VerifyTargetGraphPartition verify_process_mapping_partition.cc) -target_link_libraries(VerifyTargetGraphPartition ${Boost_LIBRARIES}) -target_link_libraries(VerifyTargetGraphPartition TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET VerifyTargetGraphPartition PROPERTY CXX_STANDARD 17) -set_property(TARGET VerifyTargetGraphPartition PROPERTY CXX_STANDARD_REQUIRED ON) +add_executable(VerifyTargetGraphPartition verify_target_graph_partition.cc) +target_link_libraries(VerifyTargetGraphPartition MtKaHyPar-BuildTools) add_executable(GridGraphGenerator grid_graph_generator.cc) -target_link_libraries(GridGraphGenerator ${Boost_LIBRARIES}) -target_link_libraries(GridGraphGenerator TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET GridGraphGenerator PROPERTY CXX_STANDARD 17) -set_property(TARGET GridGraphGenerator PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(HierarchicalTargetGraphGenerator hierarchical_process_graph_generator.cc) -target_link_libraries(HierarchicalTargetGraphGenerator ${Boost_LIBRARIES}) -target_link_libraries(HierarchicalTargetGraphGenerator TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET HierarchicalTargetGraphGenerator PROPERTY CXX_STANDARD 17) -set_property(TARGET HierarchicalTargetGraphGenerator PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(SnapToMetis snap_to_metis_converter.cc) -target_link_libraries(SnapToMetis ${Boost_LIBRARIES}) -target_link_libraries(SnapToMetis TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET SnapToMetis PROPERTY CXX_STANDARD 17) -set_property(TARGET SnapToMetis PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(GridGraphGenerator MtKaHyPar-BuildTools) + +add_executable(HierarchicalTargetGraphGenerator hierarchical_target_graph_generator.cc) +target_link_libraries(HierarchicalTargetGraphGenerator MtKaHyPar-BuildTools) add_executable(EvaluateBipart evaluate_bipart_partition.cc) -target_link_libraries(EvaluateBipart ${Boost_LIBRARIES}) -target_link_libraries(EvaluateBipart TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET EvaluateBipart PROPERTY CXX_STANDARD 17) -set_property(TARGET EvaluateBipart PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(EvaluateBipart MtKaHyPar-BuildTools) add_executable(EvaluatePartition evaluate_hmetis_partition.cc) -target_link_libraries(EvaluatePartition ${Boost_LIBRARIES}) -set_property(TARGET EvaluatePartition PROPERTY CXX_STANDARD 17) -set_property(TARGET EvaluatePartition PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(EvaluatePartition MtKaHyPar-BuildTools) add_executable(VerifyPartition verify_partition.cc) -target_link_libraries(VerifyPartition ${Boost_LIBRARIES}) -target_link_libraries(VerifyPartition TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET VerifyPartition PROPERTY CXX_STANDARD 17) -set_property(TARGET VerifyPartition PROPERTY CXX_STANDARD_REQUIRED ON) +target_link_libraries(VerifyPartition MtKaHyPar-BuildTools) add_executable(FixedVertexFileGenerator fixed_vertex_file_generator.cc) -target_link_libraries(FixedVertexFileGenerator ${Boost_LIBRARIES}) -target_link_libraries(FixedVertexFileGenerator TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET FixedVertexFileGenerator PROPERTY CXX_STANDARD 17) -set_property(TARGET FixedVertexFileGenerator PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(BenchShuffle bench_deterministic_shuffling.cpp bench_deterministic_shuffling.cpp) -target_link_libraries(BenchShuffle TBB::tbb TBB::tbbmalloc_proxy) -set_property(TARGET BenchShuffle PROPERTY CXX_STANDARD 17) -set_property(TARGET BenchShuffle PROPERTY CXX_STANDARD_REQUIRED ON) - -add_executable(MtxToGraph mtx_to_graph.cc) -set_property(TARGET MtxToGraph PROPERTY CXX_STANDARD 17) -set_property(TARGET MtxToGraph PROPERTY CXX_STANDARD_REQUIRED ON) - -set(TOOLS_TARGETS ${TOOLS_TARGETS} GraphToHgr - HgrToGraph - EvaluateBipart - VerifyPartition - EvaluatePartition - HgrToParkway - HgrToZoltan - HypergraphStats - MetisToScotch - OneToOneMapping - VerifyTargetGraphPartition - GridGraphGenerator - HierarchicalTargetGraphGenerator - FixedVertexFileGenerator - PARENT_SCOPE) +target_link_libraries(FixedVertexFileGenerator MtKaHyPar-BuildTools) diff --git a/tools/bench_deterministic_shuffling.cpp b/tools/bench_deterministic_shuffling.cc similarity index 100% rename from tools/bench_deterministic_shuffling.cpp rename to tools/bench_deterministic_shuffling.cc diff --git a/tools/hgr_to_parkway_converter.cc b/tools/hgr_to_parkway.cc similarity index 100% rename from tools/hgr_to_parkway_converter.cc rename to tools/hgr_to_parkway.cc diff --git a/tools/hgr_to_zoltan_converter.cc b/tools/hgr_to_zoltan.cc similarity index 100% rename from tools/hgr_to_zoltan_converter.cc rename to tools/hgr_to_zoltan.cc diff --git a/tools/hierarchical_process_graph_generator.cc b/tools/hierarchical_target_graph_generator.cc similarity index 100% rename from tools/hierarchical_process_graph_generator.cc rename to tools/hierarchical_target_graph_generator.cc diff --git a/tools/metis_to_scotch_converter.cc b/tools/metis_to_scotch.cc similarity index 100% rename from tools/metis_to_scotch_converter.cc rename to tools/metis_to_scotch.cc diff --git a/tools/snap_graph_to_hgr.cc b/tools/snap_to_hgr.cc similarity index 100% rename from tools/snap_graph_to_hgr.cc rename to tools/snap_to_hgr.cc diff --git a/tools/snap_to_metis_converter.cc b/tools/snap_to_metis.cc similarity index 100% rename from tools/snap_to_metis_converter.cc rename to tools/snap_to_metis.cc diff --git a/tools/verify_process_mapping_partition.cc b/tools/verify_target_graph_partition.cc similarity index 100% rename from tools/verify_process_mapping_partition.cc rename to tools/verify_target_graph_partition.cc