├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── examples ├── CMakeLists.txt ├── clang-tidy │ ├── CMakeLists.txt │ └── point.cpp ├── hello │ ├── CMakeLists.txt │ └── hello.c └── use_opencv │ ├── CMakeLists.txt │ └── use_opencv.cpp ├── plugins ├── QueryCodePage.py ├── README.md ├── asan.cmake ├── check_glibc_version.cmake ├── clang-tidy.cmake ├── cppcheck.cmake ├── cvbuild.cmake ├── debug_symbols.cmake ├── hwasan.cmake ├── msvc_EHsc.cmake ├── msvc_disable_constexpr_mutex_constructor.cmake ├── msvc_dynamic_crt.cmake ├── msvc_exception_fh3.cmake ├── msvc_ignore_no_pdb_warning.cmake ├── msvc_parallel_build.cmake ├── msvc_static_crt.cmake ├── msvc_unicode.cmake ├── msvc_utf8_encoding.cmake ├── overlook │ ├── README.md │ ├── overlook.cmake │ └── tests │ │ ├── CMakeLists.txt │ │ ├── test01.c │ │ ├── test02.c │ │ ├── test03.c │ │ ├── test04 │ │ ├── .gitignore │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── analysis-clang.md │ │ ├── analysis-gcc.md │ │ ├── analysis-msvc.md │ │ ├── cpp_clang15_disassembly_compare.webp │ │ ├── lldb_disassembly1.webp │ │ ├── lldb_disassembly2.webp │ │ ├── main.c │ │ ├── vs2022-x64-Debug.png │ │ └── vs2022-x64-RelWithDebInfo.png │ │ ├── test05.cpp │ │ ├── test06.cpp │ │ ├── test07.cpp │ │ ├── test08.cpp │ │ ├── test09.cpp │ │ ├── test10.c │ │ ├── test11.cpp │ │ ├── test12.c │ │ ├── test13.c │ │ ├── test14.c │ │ ├── test15 │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── a.c │ │ └── b.c │ │ ├── test16.cpp │ │ ├── test17 │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ ├── main.cpp │ │ ├── new │ │ │ ├── hello.c │ │ │ └── hello.h │ │ └── old │ │ │ ├── hello.c │ │ │ └── hello.h │ │ ├── test18.cpp │ │ ├── test19.cpp │ │ ├── test20.cpp │ │ ├── test21.cpp │ │ ├── test22.cpp │ │ ├── test23.cpp │ │ ├── test24.cpp │ │ ├── test25.cpp │ │ ├── test26.cpp │ │ ├── test27.cpp │ │ ├── test28.cpp │ │ ├── test29.cpp │ │ ├── test30.cpp │ │ ├── test31 │ │ ├── CMakeLists.txt │ │ ├── main.cpp │ │ └── test.c │ │ ├── test32.cpp │ │ ├── test33.cpp │ │ ├── test34.cpp │ │ ├── test35.cpp │ │ ├── test36.cpp │ │ ├── test37.cpp │ │ ├── test38.cpp │ │ ├── test39.cpp │ │ └── testX │ │ ├── CMakeLists.txt │ │ ├── README.md │ │ └── main.cpp ├── pdbdump.c ├── postfix.cmake ├── properties.cmake ├── source_group.cmake ├── summary.cmake └── tsan.cmake ├── rocbuild.cmake ├── rocpkg.py ├── rocsetup.cmake ├── test.py └── tests ├── artifacts_path ├── CMakeLists.txt └── sub │ └── CMakeLists.txt ├── asan ├── CMakeLists.txt ├── basic-global-overflow.cpp ├── matrix.hpp ├── test_matrix.cpp └── use_opencv.cpp ├── copy_dlls ├── CMakeLists.txt └── test.c ├── debug_postfix └── CMakeLists.txt ├── hide_symbols └── CMakeLists.txt ├── link_as_needed ├── CMakeLists.txt ├── foo_math.c └── foo_math.h ├── lldb_string ├── CMakeLists.txt └── main.cpp ├── msvc_utf8_encoding ├── CMakeLists.txt └── test.cpp ├── src ├── bar.c ├── bar.h ├── bar_internal.c ├── bar_internal.h ├── baz.c ├── baz.h ├── foo.c ├── foo.h └── hello.c └── unused_data_and_function ├── CMakeLists.txt └── test.c /.editorconfig: -------------------------------------------------------------------------------- 1 | # https://editorconfig.org/ 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | 8 | [*.{h,hpp,c,cpp}] 9 | indent_size = 4 10 | 11 | [{CMakeLists.*,*.cmake}] 12 | indent_size = 2 13 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CMake Build 2 | 3 | on: 4 | push: 5 | branches: 6 | - '**' 7 | pull_request: 8 | branches: 9 | - '**' 10 | 11 | jobs: 12 | build_linux: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout code 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up CMake 19 | uses: lukka/get-cmake@latest 20 | with: 21 | cmakeVersion: "~3.31.0" 22 | ninjaVersion: "^1.12.1" 23 | 24 | - name: Build 25 | run: python test.py 26 | 27 | build_windows: 28 | runs-on: windows-latest 29 | steps: 30 | - name: Checkout code 31 | uses: actions/checkout@v4 32 | 33 | - name: Set up CMake 34 | uses: lukka/get-cmake@latest 35 | with: 36 | cmakeVersion: "~3.31.0" 37 | ninjaVersion: "^1.12.1" 38 | 39 | - name: "Enter Visual Studio Developer Command Prompt" 40 | uses: TheMrMilchmann/setup-msvc-dev@v3 41 | with: 42 | arch: x64 43 | 44 | - name: Build 45 | run: python test.py 46 | 47 | build_macos: 48 | runs-on: macos-latest 49 | steps: 50 | - name: Checkout code 51 | uses: actions/checkout@v4 52 | 53 | - name: Set up CMake 54 | uses: lukka/get-cmake@latest 55 | with: 56 | cmakeVersion: "~3.31.0" 57 | ninjaVersion: "^1.12.1" 58 | 59 | - name: Build 60 | run: python test.py 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | cmake-build-*/ 3 | .cache/ 4 | .vscode/ 5 | .vs/ 6 | .idea/ 7 | __pycache__/ 8 | .DS_Store 9 | a.out 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-2024 Zhuo Zhang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RocBuild 2 | 3 | ![Build Status](https://github.com/zchrissirhcz/rocbuild/actions/workflows/build.yml/badge.svg) 4 | 5 | ## rocsetup.cmake 6 | 7 | [rocsetup.cmake](rocsetup.cmake) is a starter program for CMake configure step. 8 | 9 | Usage: 10 | ```pwsh 11 | cmake -P rocsetup.cmake -p vs2022 -a x64 -S . -B build 12 | ``` 13 | 14 | Will parse and then run: 15 | ```pwsh 16 | cmake -S . -B build -G "Visual Studio 17 2022" -A x64 17 | ``` 18 | 19 | ## rocbuild.cmake 20 | 21 | [rocbuild.cmake](rocbuild.cmake) is a set of functions/macros for daily building opeorations: 22 | - use `CMAKE_BINARY_DIR` as output location for artifacts: `.a/.lib/.dll/.so/.exe/...` 23 | - copy dlls for recursive shared dependencies 24 | - copy OpenCV's videoio plugin dlls 25 | - enable Ninja colorful output by default 26 | - set debug postfix for artifacts under Debug build type for multi-config generator 27 | - hide symbols for shared library for gcc/clang/appleclang 28 | - remove unused data/function for gcc/clang/appleclang 29 | - more fuctionalities to be added... 30 | 31 | Usage: add one line in your `CMakeLists.txt`: 32 | ```cmake 33 | include(rocbuild.cmake) 34 | ``` 35 | 36 | ## plugins 37 | 38 | [plugins directory](plugins/README.md) provides a collection of standalone cmake plugins. -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | project(RocBuildExamples) 3 | 4 | include(../rocbuild.cmake) 5 | 6 | add_subdirectory(hello) 7 | add_subdirectory(use_opencv) 8 | add_subdirectory(clang-tidy) -------------------------------------------------------------------------------- /examples/clang-tidy/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(point point.cpp) 2 | 3 | include(${CMAKE_SOURCE_DIR}/../plugins/clang-tidy.cmake) 4 | rocbuild_apply_clang_tidy("C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-tidy.exe" point) -------------------------------------------------------------------------------- /examples/clang-tidy/point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct Point { 4 | int x; 5 | int y; 6 | }; 7 | 8 | int main() 9 | { 10 | Point* p = new Point; 11 | printf("x = %d, y = %d\n", p->x, p->y); 12 | delete p; 13 | 14 | int m = 0xcdcdcdcd; 15 | printf("m = %d\n", m); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /examples/hello/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(hello hello.c) 2 | -------------------------------------------------------------------------------- /examples/hello/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("hello world\n"); 6 | return 0; 7 | } -------------------------------------------------------------------------------- /examples/use_opencv/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(OpenCV_DIR "C:/pkgs/opencv/4.10.0/x64/vc16/lib") 2 | find_package(OpenCV REQUIRED) 3 | 4 | add_executable(use_opencv use_opencv.cpp) 5 | target_link_libraries(use_opencv PRIVATE opencv_videoio opencv_highgui opencv_imgcodecs opencv_core) 6 | 7 | rocbuild_copy_dlls(use_opencv) 8 | rocbuild_copy_opencv_videoio_plugin_dlls(use_opencv) -------------------------------------------------------------------------------- /examples/use_opencv/use_opencv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | // Video parameters 6 | int frameWidth = 640; // Video width 7 | int frameHeight = 480; // Video height 8 | int fps = 1; // Frames per second (1 frame per second) 9 | int duration = 10; // Video duration in seconds 10 | int codec = cv::VideoWriter::fourcc('X', '2', '6', '4'); // H.264 codec (requires FFmpeg) 11 | std::string videoFileName = "output.mp4"; // Name of the output video file 12 | 13 | // Create a VideoWriter object to write the video 14 | cv::VideoWriter videoWriter(videoFileName, codec, fps, cv::Size(frameWidth, frameHeight)); 15 | if (!videoWriter.isOpened()) { 16 | std::cerr << "Failed to open the video file for writing! Ensure FFmpeg is installed and configured." << std::endl; 17 | return -1; 18 | } 19 | 20 | // Generate video frames with numbers 21 | for (int i = 0; i < duration; ++i) { 22 | // Create a black image as the frame 23 | cv::Mat frame(frameHeight, frameWidth, CV_8UC3, cv::Scalar(0, 0, 0)); 24 | 25 | // Draw the number on the frame 26 | std::string text = std::to_string(i); 27 | int fontFace = cv::FONT_HERSHEY_SIMPLEX; 28 | double fontScale = 4.0; 29 | int thickness = 3; 30 | cv::Size textSize = cv::getTextSize(text, fontFace, fontScale, thickness, nullptr); 31 | cv::Point textOrg((frameWidth - textSize.width) / 2, (frameHeight + textSize.height) / 2); 32 | 33 | cv::putText(frame, text, textOrg, fontFace, fontScale, cv::Scalar(0, 255, 0), thickness); 34 | 35 | // Write the frame to the video 36 | videoWriter.write(frame); 37 | } 38 | 39 | // Release the VideoWriter object 40 | videoWriter.release(); 41 | std::cout << "Video has been saved as " << videoFileName << std::endl; 42 | 43 | // Read and play the video 44 | cv::VideoCapture videoReader(videoFileName); 45 | if (!videoReader.isOpened()) { 46 | std::cerr << "Failed to open the video file for reading! Ensure FFmpeg is installed and configured." << std::endl; 47 | return -1; 48 | } 49 | 50 | cv::Mat frame; 51 | while (true) { 52 | videoReader >> frame; // Read a frame from the video 53 | if (frame.empty()) break; // If the frame is empty, the video has ended 54 | 55 | cv::imshow("Video Playback", frame); // Display the frame 56 | if (cv::waitKey(1000 / fps) == 27) break; // Exit playback if the ESC key is pressed 57 | } 58 | 59 | videoReader.release(); 60 | cv::destroyAllWindows(); 61 | return 0; 62 | } -------------------------------------------------------------------------------- /plugins/QueryCodePage.py: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz 3 | # Created: 2023-04-26 15:50:01 4 | # Last update: 2023-06-26 19:41:21 5 | 6 | import platform 7 | 8 | 9 | def is_windows(): 10 | return platform.system().lower() == "windows" 11 | 12 | 13 | if is_windows(): 14 | from winreg import ( 15 | OpenKey, 16 | QueryValueEx, 17 | HKEY_LOCAL_MACHINE, 18 | KEY_READ, 19 | ) 20 | 21 | if __name__ == "__main__": 22 | if is_windows(): 23 | root = HKEY_LOCAL_MACHINE 24 | subkey = R"SYSTEM\CurrentControlSet\Control\Nls\CodePage" 25 | 26 | key = OpenKey(root, subkey, 0, KEY_READ) 27 | name = "ACP" 28 | 29 | try: 30 | codepage, _ = QueryValueEx(key, name) 31 | print(codepage) 32 | except WindowsError: 33 | print("Failed to get code page") 34 | -------------------------------------------------------------------------------- /plugins/README.md: -------------------------------------------------------------------------------- 1 | ## asan.cmake 2 | 3 | Enable Address Sanitizer globally in your CMake-based project, by download [asan.cmake](asan.cmake) and only add one line in CMakeLists.txt 4 | ```cmake 5 | include(asan.cmake) 6 | ``` 7 | 8 | Support many compiler platforms: 9 | - GCC/Linux/Android NDK 10 | - VS2019 11 | - VS2022 12 | 13 | ## tsan.cmake 14 | 15 | Enable ThreadSanitizer globally in your CMake-based project, by download [tsan.cmake](tsan.cmake) and only add one line in CMakeLists.txt 16 | ```cmake 17 | include(tsan.cmake) 18 | ``` 19 | 20 | ## summary.cmake 21 | 22 | Get a summary message for your current build, including global stuffs and list each target, by download [summary.cmake](summary.cmake) and only add one line in CMakeLists.txt 23 | ```cmake 24 | include(summary.cmake) 25 | ``` 26 | 27 | ## msvc_utf8_encoding.cmake 28 | 29 | When you write unicode chars (e.g. Chinese characters) in utf-8 encoding source files (.c/.cpp/.h/.hpp), and your command prompt use encodings like `/cp936` (due to OS language), it prints garbage. You may avoid that by specify encoding for source files and execution, separately. 30 | 31 | Here is the tool you can use, just download [msvc_utf8_encoding.cmake](msvc_utf8_encoding.cmake) (and also [QueryCodePage.py](QueryCodePage.py) if your cmake < 3.24), and only add one line in CMakeLists.txt 32 | 33 | ```cmake 34 | include(msvc_utf8_encoding.cmake) 35 | ``` 36 | -------------------------------------------------------------------------------- /plugins/asan.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-12-12 00:14:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | option(VS2022_ASAN_DISABLE_VECTOR_ANNOTATION "Disable string annotation for VS2022 ASan?" ON) 8 | option(VS2022_ASAN_DISABLE_STRING_ANNOTATION "Disable vector annotation for VS2022 ASan?" ON) 9 | option(COPY_ASAN_DLLS "Copy ASan DLLs to binary directory?" OFF) 10 | 11 | # globally 12 | # https://stackoverflow.com/a/65019152/2999096 13 | # https://docs.microsoft.com/en-us/cpp/build/cmake-presets-vs?view=msvc-170#enable-addresssanitizer-for-windows-and-linux 14 | set(ASAN_AVAILABLE ON) 15 | if((CMAKE_C_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")) 16 | if((CMAKE_C_COMPILER_VERSION STRLESS 16.0) OR (CMAKE_CXX_COMPILER_VERSION STRLESS 16.0)) 17 | message(FATAL_ERROR "ASAN is available since VS2019, please use higher version of VS") 18 | set(ASAN_AVAILABLE OFF) 19 | elseif( ((CMAKE_C_COMPILER_VERSION STRGREATER_EQUAL 16.0) AND (CMAKE_C_COMPILER_VERSION STRLESS 16.7)) 20 | OR ((CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 16.0) AND (CMAKE_CXX_COMPILER_VERSION STRLESS 16.7)) ) 21 | # https://devblogs.microsoft.com/cppblog/asan-for-windows-x64-and-debug-build-support/ 22 | message(FATAL_ERROR "VS2019 x64 ASAN requires VS >= 16.7, please update VS") 23 | set(ASAN_AVAILABLE OFF) 24 | else() 25 | set(ASAN_OPTIONS /fsanitize=address /Zi) 26 | endif() 27 | elseif(MSVC AND ((CMAKE_C_COMPILER_ID STREQUAL "Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))) 28 | message(WARNING "Clang-CL not support setup AddressSanitizer via CMakeLists.txt") 29 | set(ASAN_AVAILABLE OFF) 30 | elseif((CMAKE_C_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 31 | OR (CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) 32 | set(ASAN_OPTIONS -fsanitize=address -fno-omit-frame-pointer -g) 33 | endif() 34 | 35 | if(ASAN_AVAILABLE) 36 | message(STATUS ">>> USE_ASAN: YES") 37 | add_compile_options(${ASAN_OPTIONS}) 38 | if((CMAKE_SYSTEM_NAME MATCHES "Windows") AND ((CMAKE_C_COMPILER_ID STREQUAL "MSVC") OR (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"))) 39 | add_link_options(/ignore:4300) # /INCREMENTAL 40 | add_link_options(/DEBUG) # LNK4302 41 | 42 | if(CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 17.2) 43 | if(VS2022_ASAN_DISABLE_VECTOR_ANNOTATION) 44 | # https://learn.microsoft.com/en-us/cpp/sanitizers/error-container-overflow?view=msvc-170 45 | add_compile_definitions(_DISABLE_VECTOR_ANNOTATION) 46 | message(STATUS ">>> VS2022_ASAN_DISABLE_VECTOR_ANNOTATION: YES") 47 | else() 48 | message(STATUS ">>> VS2022_ASAN_DISABLE_VECTOR_ANNOTATION: NO") 49 | endif() 50 | endif() 51 | 52 | if(CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 17.6) 53 | if(VS2022_ASAN_DISABLE_STRING_ANNOTATION) 54 | # https://learn.microsoft.com/en-us/cpp/sanitizers/error-container-overflow?view=msvc-170 55 | add_compile_definitions(_DISABLE_STRING_ANNOTATION) 56 | message(STATUS ">>> VS2022_ASAN_DISABLE_STRING_ANNOTATION: YES") 57 | else() 58 | message(STATUS ">>> VS2022_ASAN_DISABLE_STRING_ANNOTATION: NO") 59 | endif() 60 | endif() 61 | 62 | # https://devblogs.microsoft.com/cppblog/msvc-address-sanitizer-one-dll-for-all-runtime-configurations/ 63 | if((CMAKE_C_COMPILER_VERSION STRGREATER_EQUAL 17.7) OR (CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 17.7)) 64 | if((CMAKE_GENERATOR MATCHES "Visual Studio") AND (CMAKE_VERSION VERSION_GREATER_EQUAL "3.27")) # for running/debugging in Visual Studio 65 | if(CMAKE_GENERATOR_PLATFORM MATCHES "x64") 66 | set(CMAKE_VS_DEBUGGER_ENVIRONMENT "PATH=$(VC_ExecutablePath_x64);%PATH%\nASAN_SYMBOLIZER_PATH=$(VC_ExecutablePath_x64)") 67 | elseif(CMAKE_GENERATOR_PLATFORM MATCHES "Win32") 68 | set(CMAKE_VS_DEBUGGER_ENVIRONMENT "PATH=$(VC_ExecutablePath_x86);%PATH%\nASAN_SYMBOLIZER_PATH=$(VC_ExecutablePath_x86)") 69 | endif() 70 | endif() 71 | 72 | if((CMAKE_GENERATOR MATCHES "Ninja") OR COPY_ASAN_DLLS OR 73 | ((CMAKE_GENERATOR MATCHES "Visual Studio") AND (CMAKE_VERSION VERSION_LESS "3.27")) ) 74 | get_filename_component(COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY) 75 | file(GLOB ASAN_DLLS "${COMPILER_DIR}/clang_rt.asan_dynamic*.dll") 76 | foreach(ASAN_DLL ${ASAN_DLLS}) 77 | if(DEFINED CMAKE_CONFIGURATION_TYPES) 78 | foreach(CONFIG_TYPE ${CMAKE_CONFIGURATION_TYPES}) 79 | file(COPY "${ASAN_DLL}" DESTINATION ${CMAKE_BINARY_DIR}/${CONFIG_TYPE}) 80 | endforeach() 81 | else() 82 | file(COPY "${ASAN_DLL}" DESTINATION ${CMAKE_BINARY_DIR}) 83 | endif() 84 | endforeach() 85 | unset(COMPILER_DIR) 86 | unset(ASAN_DLLS) 87 | endif() 88 | endif() 89 | 90 | else() 91 | add_link_options(${ASAN_OPTIONS}) 92 | endif() 93 | else() 94 | message(STATUS ">>> USE_ASAN: NO") 95 | endif() 96 | 97 | 98 | # per-target 99 | # https://developer.android.com/ndk/guides/asan?hl=zh-cn#cmake 100 | # target_compile_options(${TARGET} PUBLIC -fsanitize=address -fno-omit-frame-pointer -g) 101 | # set_target_properties(${TARGET} PROPERTIES LINK_FLAGS -fsanitize=address) # for non-INTERFACE targets 102 | # target_link_options(${TARGET} INTERFACE -fsanitize=address) # for INTERFACE targets 103 | -------------------------------------------------------------------------------- /plugins/check_glibc_version.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-12 00:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | function(CHECK_GLIBC_VERSION FOUND_GLIBC GLIBC_VERSION) 8 | # currently we only consider GCC and Clang for GLIBC version determination 9 | # AppleClang is ignored 10 | set(FOUND_GLIBC FALSE) 11 | set(GLIBC_VERSION "") 12 | if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") 13 | set(FOUND_GLIBC TRUE) 14 | execute_process ( 15 | COMMAND ${CMAKE_C_COMPILER} -print-file-name=libc.so.6 16 | OUTPUT_VARIABLE GLIBC_PATH 17 | OUTPUT_STRIP_TRAILING_WHITESPACE) 18 | 19 | execute_process ( 20 | COMMAND ${GLIBC_PATH} 21 | OUTPUT_VARIABLE GLIBC_OUTPUT 22 | OUTPUT_STRIP_TRAILING_WHITESPACE) 23 | 24 | # convert \n to ; and remove the last ; 25 | string (REPLACE "\n" ";" GLIBC_OUTPUT ${GLIBC_OUTPUT}) 26 | # only keep the first element 27 | list (GET GLIBC_OUTPUT 0 first_line) 28 | # convert space to ; and remove the last ; 29 | string (REPLACE " " ";" first_line ${first_line}) 30 | # only keep the last element 31 | list(LENGTH first_line len) 32 | math(EXPR last_index "${len} - 1") 33 | list(GET first_line ${last_index} GLIBC_VERSION) 34 | # GLIBC_VERSION should ends with number, other stuff should be removed 35 | string(REGEX REPLACE "[^0-9]$" "" GLIBC_VERSION ${GLIBC_VERSION}) 36 | endif() 37 | 38 | set(FOUND_GLIBC ${FOUND_GLIBC} PARENT_SCOPE) 39 | set(GLIBC_VERSION ${GLIBC_VERSION} PARENT_SCOPE) 40 | endfunction() -------------------------------------------------------------------------------- /plugins/clang-tidy.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Create: 2025-03-09 15:08:06 4 | # Modify: 2025-03-21 22:08:00 5 | 6 | # This cmake plugin let you run clang-tidy on specified target 7 | # Each time you run "make", it report warnings if potential bug found 8 | # 9 | # Usage: 10 | # include(clang-tidy.cmake) 11 | # rocbuild_apply_clang_tidy(clang-tidy-executable target) 12 | # 13 | # e.g. 14 | # # VS2022 15 | # rocbuild_apply_clang_tidy("C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-tidy.exe" main) 16 | # 17 | # # ubuntu 22.04 18 | # rocbuild_apply_clang_tidy(clang-tidy-18 main) 19 | # 20 | # # macOS 21 | # rocbuild_apply_clang_tidy("/Users/zz/soft/LLVM-20.1.1-macOS-ARM64/bin/clang-tidy" main) 22 | # 23 | 24 | cmake_minimum_required(VERSION 3.15) 25 | include_guard() 26 | 27 | 28 | # Apply clang-tidy on source files of given target 29 | # CLANG_TIDY_EXECUTABLE: clang-tidy executable file path 30 | # - Ubuntu: https://apt.llvm.org/ 31 | # - Windows: "https://github.com/llvm/llvm-project/releases/" 32 | # - Windows with VS2022: "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-tidy.exe" 33 | # - Android NDK on Windows: don't use NDK's clang-tidy.exe. Use "clang-tidy" instead. 34 | # TARGET: target name 35 | function(rocbuild_apply_clang_tidy CLANG_TIDY_EXECUTABLE TARGET) 36 | # collecting absolute paths for each source file in the given target 37 | get_target_property(target_sources ${TARGET} SOURCES) 38 | get_target_property(target_source_dir ${TARGET} SOURCE_DIR) 39 | # message(STATUS "target_source_dir: ${target_source_dir}") 40 | # message(STATUS "target_sources:") 41 | set(src_path_lst "") 42 | foreach(target_source ${target_sources}) 43 | # message(STATUS " ${target_source}") 44 | if(IS_ABSOLUTE ${target_source}) 45 | set(target_source_absolute_path ${target_source}) 46 | else() 47 | set(target_source_absolute_path ${target_source_dir}/${target_source}) 48 | endif() 49 | list(APPEND src_path_lst ${target_source_absolute_path}) 50 | endforeach() 51 | 52 | # prepare clang-tidy command with arguments 53 | set(clang_tidy_full_command "${CLANG_TIDY_EXECUTABLE}") 54 | list(APPEND clang_tidy_full_command "-p") 55 | list(APPEND clang_tidy_full_command "${CMAKE_BINARY_DIR}") 56 | list(APPEND clang_tidy_full_command "${src_path_lst}") 57 | 58 | list(APPEND clang_tidy_full_command "--use-color") 59 | 60 | if(APPLE) 61 | list(APPEND clang_tidy_full_command "--") 62 | list(APPEND clang_tidy_full_command "-isysroot") 63 | list(APPEND clang_tidy_full_command "${CMAKE_OSX_SYSROOT}") 64 | endif() 65 | 66 | if(CMAKE_CROSSCOMPILING AND (CMAKE_SYSTEM_NAME STREQUAL "QNX")) 67 | list(APPEND clang_tidy_full_command "--") 68 | list(APPEND clang_tidy_full_command "-isysroot") 69 | list(APPEND clang_tidy_full_command "${QNX_TARGET}") 70 | endif() 71 | 72 | add_custom_target( 73 | clang-tidy_${TARGET} 74 | COMMAND ${clang_tidy_full_command} 75 | ) 76 | add_dependencies(${TARGET} clang-tidy_${TARGET}) 77 | endfunction() 78 | -------------------------------------------------------------------------------- /plugins/cppcheck.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2025-04-29 08:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Apply cppcheck on source files of given target 8 | # Example usage: 9 | # add_executable(hello hello.cpp) 10 | # apply_cppcheck(hello) 11 | function(apply_cppcheck TARGET) 12 | find_program(CMAKE_CXX_CPPCHECK NAMES cppcheck) 13 | 14 | # collecting absolute paths for each source file in the given target 15 | get_target_property(target_sources ${TARGET} SOURCES) 16 | get_target_property(target_source_dir ${TARGET} SOURCE_DIR) 17 | set(src_path_lst "") 18 | foreach(target_source ${target_sources}) 19 | if(IS_ABSOLUTE ${target_source}) 20 | set(target_source_absolute_path ${target_source}) 21 | else() 22 | set(target_source_absolute_path ${target_source_dir}/${target_source}) 23 | endif() 24 | list(APPEND src_path_lst ${target_source_absolute_path}) 25 | endforeach() 26 | 27 | set(cppcheck_raw_command "cppcheck --enable=warning --inconclusive --force --inline-suppr ${src_path_lst}") 28 | string(REPLACE " " ";" cppcheck_converted_command "${cppcheck_raw_command}") 29 | add_custom_target( 30 | cppcheck_${TARGET} 31 | COMMAND ${cppcheck_converted_command} 32 | ) 33 | add_dependencies(${TARGET} cppcheck_${TARGET}) 34 | endfunction() -------------------------------------------------------------------------------- /plugins/cvbuild.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-12 00:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | set(CVBUILD_VERSION "2024.06.12") 8 | 9 | ############################################################### 10 | # 11 | # Platform determinations 12 | # 13 | ############################################################### 14 | if(CMAKE_SYSTEM_NAME MATCHES "Windows") 15 | set(CVBUILD_PLATFORM "windows") 16 | elseif(ANDROID) 17 | set(CVBUILD_PLATFORM "android") 18 | elseif(CMAKE_SYSTEM_NAME MATCHES "Linux") 19 | set(CVBUILD_PLATFORM "linux") 20 | elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") 21 | set(CVBUILD_PLATFORM "mac") 22 | else() 23 | message(FATAL_ERROR "un-configured platform: ${CMAKE_SYSTEM_NAME}") 24 | endif() 25 | if(CVBUILD_VERBOSE) 26 | message(STATUS "----- CVBUILD_PLATFORM: ${CVBUILD_PLATFORM}") 27 | endif() 28 | 29 | ############################################################### 30 | # 31 | # Architecture determinations 32 | # 33 | ############################################################### 34 | if((IOS AND CMAKE_OSX_ARCHITECTURES MATCHES "arm") 35 | OR (CMAKE_SYSTEM_PROCESSOR MATCHES "^(arm|Arm|ARM|aarch64|AAarch64|AARCH64)")) 36 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 37 | set(CVBUILD_ARCH arm64) 38 | else() 39 | set(CVBUILD_ARCH arm32) 40 | endif() 41 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(mips|Mips|MIPS)") 42 | set(CVBUILD_ARCH mips) 43 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(riscv|Riscv|RISCV)") 44 | set(CVBUILD_ARCH riscv) 45 | elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|PowerPC|POWERPC)") 46 | set(CVBUILD_ARCH powerpc) 47 | else() 48 | set(CVBUILD_ARCH x86) 49 | #if(CMAKE_SYSTEM_NAME STREQUAL "Emscripten") #wasm 50 | #endif() 51 | endif() 52 | if (CVBUILD_VERBOSE) 53 | message(STATUS "----- CVBUILD_ARCH: ${CVBUILD_ARCH}") 54 | endif() 55 | 56 | ############################################################### 57 | # 58 | # ABI determinations 59 | # 60 | ############################################################### 61 | if (ANDROID) 62 | set(CVBUILD_ABI ${ANDROID_ABI}) 63 | elseif(CVBUILD_ARCH STREQUAL x86) 64 | if(CMAKE_SIZEOF_VOID_P EQUAL 8) 65 | set(CVBUILD_ABI "x64") 66 | else() 67 | set(CVBUILD_ABI "x86") 68 | endif() 69 | elseif(CVBUILD_ARCH MATCHES arm) 70 | # determine ARCH from compiler name. Note: we can't use MATCHES for c++ compiler, since `++` failed for regular expression 71 | if(CMAKE_C_COMPILER MATCHES "aarch64-linux-gnu-gcc") 72 | set(CVBUILD_ABI "aarch64") 73 | elseif(CMAKE_C_COMPILER MATCHES "arm-linux-gnueabihf-gcc") 74 | set(CVBUILD_ABI "arm-eabihf") 75 | elseif(CMAKE_C_COMPILER MATCHES "aarch64-none-linux-gnu-gcc") 76 | set(CVBUILD_ABI "aarch64") 77 | elseif(NOT CMAKE_CROSS_COMPILATION) 78 | if(CMAKE_SYSTEM_NAME MATCHES "Darwin") 79 | set(CVBUILD_ABI "aarch64") 80 | else() 81 | message(FATAL_ERROR "un-assigned ABI, please add it now") 82 | endif() 83 | else() 84 | message(FATAL_ERROR "un-assigned ABI, please add it now") 85 | endif() 86 | else() 87 | message(FATAL_ERROR "un-assigned ABI, please add it now") 88 | endif() 89 | if (CVBUILD_VERBOSE) 90 | message(STATUS "----- CVBUILD_ABI: ${CVBUILD_ABI}") 91 | endif() 92 | 93 | ############################################################### 94 | # 95 | # Visual Studio stuffs: vs_version, vc_version 96 | # 97 | ############################################################### 98 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 99 | if(MSVC_VERSION EQUAL 1600) 100 | set(vs_version vs2010) 101 | set(vc_version vc10) 102 | elseif(MSVC_VERSION EQUAL 1700) 103 | set(vs_version vs2012) 104 | set(vc_version vc11) 105 | elseif(MSVC_VERSION EQUAL 1800) 106 | set(vs_version vs2013) 107 | set(vc_version vc12) 108 | elseif(MSVC_VERSION EQUAL 1900) 109 | set(vs_version vs2015) 110 | set(vc_version vc14) 111 | elseif(MSVC_VERSION GREATER_EQUAL 1910 AND MSVC_VERSION LESS_EQUAL 1920) 112 | set(vs_version vs2017) 113 | set(vc_version vc15) 114 | elseif(MSVC_VERSION GREATER_EQUAL 1920 AND MSVC_VERSION LESS_EQUAL 1930) 115 | set(vs_version vs2019) 116 | set(vc_version vc16) 117 | elseif(MSVC_VERSION GREATER_EQUAL 1930) 118 | set(vs_version vs2022) 119 | set(vc_version vc17) 120 | endif() 121 | endif() 122 | -------------------------------------------------------------------------------- /plugins/debug_symbols.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-13 23:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | add_compile_options( 8 | "$<$:/Zi>" 9 | "$<$:/Zi>" 10 | 11 | "$<$:-g>" 12 | "$<$:-g>" 13 | 14 | "$<$:-fstandalone-debug>" 15 | "$<$:-fstandalone-debug>" 16 | ) 17 | -------------------------------------------------------------------------------- /plugins/hwasan.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-11-14 22:50:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # https://developer.android.google.cn/ndk/guides/hwasan#ndk-build 8 | if(ANDROID) 9 | # Note: `-g` is explicitly required here for debug symbol information such line number and file name 10 | # There is NDK's android.toolchain.cmake's `-g`, in case user removed it, explicitly add `-g` here. 11 | set(HWASAN_OPTIONS -fsanitize=hwaddress -fno-omit-frame-pointer -g) 12 | else() 13 | message(FATAL_ERROR "HWASan is only supported by Android") 14 | endif() 15 | 16 | # 1. NDK 21 17 | if((CMAKE_CXX_COMPILER_ID STREQUAL "Clang") AND (CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 9.0)) 18 | message(STATUS "HWASan check: NDK version OK") 19 | else() 20 | message(FATAL_ERROR "HWSAsan check failed: requires NDK >= r21") 21 | endif() 22 | 23 | # 2. API 24 | if(ANDROID_NATIVE_API_LEVEL LESS 29) 25 | message(FATAL_ERROR "HWASan check failed: requires ANDROID_NATIVE_API_LEVEL >= 29") 26 | else() 27 | message(STATUS "HWASan check: ANDROID_NATIVE_API_LEVEL OK") 28 | endif() 29 | 30 | # 3. arm64 31 | if(ANDROID_ABI STREQUAL "arm64-v8a") 32 | message(STATUS "HWASan check: ANDROID_ABI OK") 33 | else() 34 | message(FATAL_ERROR "HWASan only works for ANDROID_ABI=armv8-a") 35 | endif() 36 | 37 | message(STATUS "Using HWASAN: YES") 38 | add_compile_options(${HWASAN_OPTIONS}) 39 | add_link_options(${HWASAN_OPTIONS}) 40 | -------------------------------------------------------------------------------- /plugins/msvc_EHsc.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-12 00:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 8 | add_compile_options("/EHsc") 9 | endif() -------------------------------------------------------------------------------- /plugins/msvc_disable_constexpr_mutex_constructor.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-11 23:48:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # When using VS2022 >= 17.10.0, and C:/Windows/System32/msvcp140.dll version < 14.40.0 8 | # people meet crash in Release or RelWithDebInfo configuration, with error message: 9 | # > 0xC0000005: Access violation reading location 0x0000000000000000. 10 | # 11 | # this runtime error can be reproduces with simple code that using `std::mutex`: 12 | # // https://github.com/microsoft/STL/issues/4730 13 | # #include 14 | # #include 15 | # std::mutex mtx; 16 | # 17 | # void testmethod() { 18 | # std::scoped_lock lock{ mtx }; 19 | # std::cout << "lock worked!\n"; 20 | # } 21 | # int main() 22 | # { 23 | # std::cout << "Start!\n"; 24 | # testmethod(); 25 | # std::cout << "End!\n"; 26 | # return 0; 27 | # } 28 | # 29 | # Or, people are using spdlog, even don't know what `std::mutex` is, also suffer same crash with minimal code: 30 | # // https://github.com/gabime/spdlog/issues/2902 31 | # #include 32 | # int main() 33 | # { 34 | # SPDLOG_INFO("x"); 35 | # return 0; 36 | # } 37 | # 38 | # The short solution is define `_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR` macro. 39 | # The long term solution is update both "Visual Studio 2022" and "Microsoft Visual C++ 2015-2022 Redistributable package" to the latest 40 | # And when `C:\Windows\System32\msvcp140.dll` is silently downgraded to < 14.40, people may: 41 | # - Repair it in control panel, even it shows a misleading new version 42 | # - Determine version in PowerShell by: `echo ((Get-Command C:\Windows\System32\msvcp140.dll).Version)` 43 | # - Detect it first (in CMakeLists.txt), then define `_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR` 44 | # 45 | # https://github.com/gabime/spdlog/issues/2902 46 | # https://github.com/microsoft/STL/issues/2285 47 | # https://github.com/microsoft/STL/wiki/Changelog#vs-2022-1710 48 | # https://stackoverflow.com/questions/78598141/first-stdmutexlock-crashes-in-application-built-with-latest-visual-studio/78599923#78599923 49 | # https://learn.microsoft.com/en-us/cpp/windows/redistributing-visual-cpp-files?view=msvc-170 50 | # https://learn.microsoft.com/en-us/cpp/windows/determining-which-dlls-to-redistribute?view=msvc-170 51 | if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") AND (CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 17.10)) 52 | set(DLL_PATH "C:/Windows/System32/msvcp140.dll") 53 | 54 | # PowerShell command to get the version of the DLL and format it 55 | set(PS_COMMAND "[System.String]::Join('.', ((Get-Command ${DLL_PATH}).Version.Major, (Get-Command ${DLL_PATH}).Version.Minor, (Get-Command ${DLL_PATH}).Version.Build, (Get-Command ${DLL_PATH}).Version.Revision))") 56 | 57 | execute_process( 58 | COMMAND powershell -NoProfile -ExecutionPolicy Bypass -Command ${PS_COMMAND} 59 | OUTPUT_VARIABLE MSVCP140_DLL_VERSION 60 | ERROR_VARIABLE ERROR_OUTPUT 61 | RESULT_VARIABLE RESULT 62 | ) 63 | 64 | if(RESULT EQUAL 0) 65 | string(STRIP "${MSVCP140_DLL_VERSION}" MSVCP140_DLL_VERSION) # Remove any trailing newlines or spaces 66 | message(STATUS "${DLL_PATH} version: ${MSVCP140_DLL_VERSION}") 67 | if(MSVCP140_DLL_VERSION STRGREATER_EQUAL 14.40) 68 | add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) 69 | endif() 70 | else() 71 | message(FATAL_ERROR "Failed to get DLL version: ${ERROR_OUTPUT}") 72 | endif() 73 | 74 | unset(PS_COMMAND) 75 | unset(DLL_PATH) 76 | endif() 77 | -------------------------------------------------------------------------------- /plugins/msvc_dynamic_crt.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-12 00:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Enables use of dynamically linked CRT 8 | # i.e. use MD / MDd 9 | 10 | # 设置策略CMP0091为NEW,新策略 11 | if (POLICY CMP0091) 12 | cmake_policy(SET CMP0091 NEW) 13 | endif (POLICY CMP0091) 14 | 15 | if(MSVC AND NOT CMAKE_VERSION VERSION_LESS "3.15") 16 | # cmake before version 3.15 not work 17 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$:Debug>") 18 | endif() -------------------------------------------------------------------------------- /plugins/msvc_exception_fh3.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-30 13:08 :00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Scenario: 8 | # - build an library `hello` with VS2019 >= 16.3 (or VS2022), which uses Frame Handler 4 on default (`__CxxFrameHandler4`) 9 | # - link this library `hello` in VS2017/VS2015, or VS2019 < 16.3, which uses Frame Handler 3 on default (`__CxxFrameHandler3`) 10 | # - then comes link error: unresolved external symbol __CxxFrameHandler4 11 | # For a full example, see https://github.com/zchrissirhcz/min-repros/tree/master/test_GS_EHsc_link_error 12 | # 13 | 14 | option(USE_COMPATIBLE_FRAME_HANDLER_FOR_VS "Switch off FH4 feature(then use FH3) for compatibility?" ON) 15 | 16 | if(USE_COMPATIBLE_FRAME_HANDLER_FOR_VS) 17 | if((CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") AND (CMAKE_CXX_COMPILER_VERSION STRGREATER_EQUAL 16.3)) 18 | # https://devblogs.microsoft.com/cppblog/making-cpp-exception-handling-smaller-x64 19 | # https://devblogs.microsoft.com/cppblog/msvc-backend-updates-in-visual-studio-2019-version-16-2/ 20 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /d2FH4-") # Disable FH4, means use FH3 21 | # You may also manually turn this on by: 22 | # VS2019->Properties->C/C++->Command Line add '-d2FH4-' 23 | 24 | # TODO: is link options also required? 25 | # VS2019->Properties->Linker->Command Line add '-d2:-FH4-' 26 | endif() 27 | message(STATUS ">>> USE_COMPATIBLE_FRAME_HANDLER_FOR_VS: YES") 28 | else() 29 | message(STATUS ">>> USE_COMPATIBLE_FRAME_HANDLER_FOR_VS: NO") 30 | endif() -------------------------------------------------------------------------------- /plugins/msvc_ignore_no_pdb_warning.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-12 00:00:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | #set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS "/ignore:4099") 8 | add_link_options( 9 | "$<$:/ignore:4099>" 10 | "$<$:/ignore:4099>" 11 | ) 12 | -------------------------------------------------------------------------------- /plugins/msvc_parallel_build.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # cmake's -j or --parallel option does not work for msbuild 8 | # let's do parallel build by pasing /MP to cl.exe 9 | 10 | # https://zhuanlan.zhihu.com/p/628860221 11 | # 高版本已被废弃,但是低版本的Gm会影响并行 12 | add_compile_options($<$:/Gm->) 13 | add_compile_options($<$:/Gm->) 14 | cmake_host_system_information(RESULT CPU_NUMBER_OF_LOGICAL_CORES QUERY NUMBER_OF_LOGICAL_CORES) 15 | # NOTE: not all of the CPU's are used for code building to make UI responsible 16 | math(EXPR PARALLEL_BUILD_PROCESSR_COUNT "${CPU_NUMBER_OF_LOGICAL_CORES}/2") 17 | add_compile_options($<$:/MP${PARALLEL_BUILD_PROCESSR_COUNT}>) 18 | add_compile_options($<$:/MP${PARALLEL_BUILD_PROCESSR_COUNT}>) 19 | -------------------------------------------------------------------------------- /plugins/msvc_static_crt.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Enables use of statically linked CRT for statically linked target 8 | # i.e. use MT / MTd 9 | 10 | if(MSVC) 11 | message(STATUS ">>> USE_MSVC_STATIC_CRT: YES") 12 | message(STATUS ">>> CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 13 | 14 | if(POLICY CMP0091) 15 | cmake_policy(SET CMP0091 NEW) 16 | endif (POLICY CMP0091) 17 | 18 | if(NOT CMAKE_VERSION VERSION_LESS "3.15") 19 | set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") 20 | elseif(CMAKE_BUILD_TYPE MATCHES "Debug") 21 | set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") 22 | set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd") 23 | elseif(CMAKE_BUILD_TYPE MATCHES "Release") 24 | set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") 25 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT") 26 | elseif(CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo") 27 | set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_DEBUG} /MTd") 28 | set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_DEBUG} /MTd") 29 | elseif(CMAKE_BUILD_TYPE MATCHES "MinSizeRel") 30 | set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_RELEASE} /MT") 31 | set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_RELEASE} /MT") 32 | endif() 33 | endif() 34 | 35 | -------------------------------------------------------------------------------- /plugins/msvc_unicode.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # CMake generated Visual Studio Solution is multi-byte character on default 8 | # VS2022 generated console application is unicode on default 9 | # https://github.com/Jebbs/DSFML-C/issues/8 10 | if (MSVC) 11 | add_compile_definitions(UNICODE _UNICODE) 12 | endif() 13 | 14 | -------------------------------------------------------------------------------- /plugins/msvc_utf8_encoding.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-11 23:48:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Set source file utf-8 encoding 8 | # This solves Visual Studio warning C4819 9 | add_compile_options( 10 | "$<$:/source-charset:utf-8>" 11 | "$<$:/source-charset:utf-8>" 12 | ) 13 | 14 | # Set executable run with utf-8 encoding 15 | if(WIN32) 16 | if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24) 17 | cmake_host_system_information( 18 | RESULT CodePage 19 | QUERY WINDOWS_REGISTRY "HKLM/SYSTEM/CurrentControlSet/Control/Nls/CodePage" 20 | VALUE "ACP" 21 | ) 22 | else() 23 | include(FindPythonInterp) 24 | execute_process( 25 | COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_SOURCE_DIR}/cmake/QueryCodePage.py" 26 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 27 | RESULT_VARIABLE ReturnCode 28 | OUTPUT_VARIABLE CodePage 29 | ) 30 | endif() 31 | if("${CodePage}" STREQUAL "936") 32 | add_compile_options( 33 | "$<$:/execution-charset:gbk>" 34 | "$<$:/execution-charset:gbk>" 35 | ) 36 | endif() 37 | endif() 38 | -------------------------------------------------------------------------------- /plugins/overlook/README.md: -------------------------------------------------------------------------------- 1 | # Overlook 2 | 3 | Overlook: a cmake plugin for safer c/c++ programming. 4 | 5 | ## Introduction 6 | 7 | [overlook.cmake](overlook.cmake) collects 30+ warnings, mark them as errors, help you found bugs when compile C/C++ code. 8 | 9 | ## Usage 10 | 11 | Download [overlook.cmake](https://github.com/zchrissirhcz/rocbuild/blob/main/overlook/overlook.cmake) and included it in `CMakeLists.txt`, enable its compile options at your required level: 12 | 13 | ### Case1: enable overlook globally 14 | 15 | ```cmake 16 | include("overlook.cmake") 17 | ``` 18 | 19 | ### Case2: enable overlook on target level 20 | 21 | ```cmake 22 | set(OVERLOOK_GLOBAL OFF) 23 | include("overlook.cmake") 24 | add_library(hello STATIC hello.c) 25 | target_link_libraries(hello PRIVATE overlook) 26 | ``` 27 | 28 | or: 29 | ```cmake 30 | set(OVERLOOK_GLOBAL OFF) 31 | include("overlook.cmake") 32 | add_library(world STATIC world.cpp) 33 | target_compile_options(world PRIVATE 34 | ${OVERLOOK_CXX_COMPILE_OPTIONS} # C++ 35 | # ${OVERLOOK_C_COMPILE_OPTIONS} # C 36 | ) 37 | ``` 38 | 39 | ### Case3: enable overlook on file level 40 | 41 | ```cmake 42 | set(OVERLOOK_GLOBAL OFF) 43 | include("overlook.cmake") 44 | add_library(hello foo.c bar.cpp) 45 | set_source_files_properties(foo.c PROPERTIES COMPILE_OPTIONS 46 | ${OVERLOOK_C_COMPILE_OPTIONS} 47 | ) 48 | ``` 49 | 50 | Then compile your projec as usual, it will report bugs more seriously thanks to overlook. 51 | 52 | ## Purpose 53 | 54 | Good programmers should not ignore warnings. Treating all warnings as errors, however, is not practical due to reasons: 55 | - time cost 56 | - not own scratch project, too much to modify 57 | - not affect result 58 | 59 | Moreover, on the GCC/Clang common flags: 60 | - `-Wall` does not mean `turn on all warnings`, missing flags like `-Wnon-virtual-dtor` 61 | - `-Wpedantic` check more flags that `-Wall`, but still missing flags like `-Wnon-virtual-dtor` 62 | - `-Weffc++` may cover more flags 63 | 64 | Here comes the contradiction: which warnings should be considered carefully? 65 | 66 | In [overlook.cmake](overlook.cmake), there are **39 serious compilation warnings' checking, treat corresponding C/C++ flags as error**, with corresponding unit tests (See [tests](tests)). Most are extracted from practical cross-platform projects, and does resolve severe bugs such as: 67 | - Segmentation Faults(caused by address truncation) 68 | - Memory leaks(caused by missing including header file) 69 | - Trap(caused by missing return value) 70 | 71 | These severe bugs can not be inspected by famous tools like AddressSanitizer, Valgrind, VLD, but [overlook.cmake](overlook.cmake) can. People may also use [clang-tidy](https://clang.llvm.org/extra/clang-tidy/), which will report more compile warnings (instead of compile errors). 72 | 73 | 74 | ## Advanced Usage 75 | 76 | ### Disable a specific warning 77 | 78 | Compile your code with overlook.cmake applyed, see that error nessage's type/number, search it in overlook.cmake and comment it out via inserting `#`, such as: 79 | ```cmake 80 | #if(OVERLOOK_ENABLE_RULE32) 81 | # if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 82 | # if(CMAKE_CXX_COMPILER_VERSION GREATER 7.5) 83 | # list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=class-memaccess) 84 | # endif() 85 | # endif() 86 | #endif() 87 | ``` 88 | 89 | ### Debugging 90 | 91 | If you're using Overlook, but it seems not work, possible cases: 92 | 93 | 1. The overlook.cmake you are using is not the latest. 94 | 2. Overlook's rules are suppressed due to your `add_definitions(-w)`, which ignore all warnings thus overlook won't work. 95 | 3. Your compiler is not covered by Overlook. If so, feel free to create a Pull Request or open an issue. 96 | 97 | ## References 98 | 99 | - https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines 100 | - https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html 101 | -------------------------------------------------------------------------------- /plugins/overlook/overlook.cmake: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # 3 | # Overlook: a cmake plugin for safer c/c++ programming. 4 | # 5 | # Author: Zhuo Zhang 6 | # Homepage: https://github.com/zchrissirhcz/rocbuild 7 | # 8 | ############################################################### 9 | 10 | cmake_minimum_required(VERSION 3.20) 11 | include_guard() 12 | 13 | set(OVERLOOK "${CMAKE_CURRENT_LIST_FILE}") 14 | 15 | set(OVERLOOK_VERSION "2025.04.14") 16 | option(OVERLOOK_GLOBAL "Apply overlook globally?" ON) 17 | 18 | set(OVERLOOK_C_COMPILE_OPTIONS) 19 | set(OVERLOOK_CXX_COMPILE_OPTIONS) 20 | 21 | # Print overlook information 22 | message("----------------------------------------------------------") 23 | message(" Overlook: a cmake tool for safer C/C++ programming ") 24 | message(" Author : Zhuo Zhang (imzhuo@foxmail.com) ") 25 | message(" Homepage: https://github.com/zchrissirhcz/rocbuild ") 26 | message(" Version : ${OVERLOOK_VERSION} ") 27 | message("----------------------------------------------------------") 28 | 29 | if(CMAKE_C_COMPILER_ID) 30 | set(OVERLOOK_WITH_C TRUE) 31 | else() 32 | set(OVERLOOK_WITH_C FALSE) 33 | endif() 34 | 35 | if(CMAKE_CXX_COMPILER_ID) 36 | set(OVERLOOK_WITH_CXX TRUE) 37 | else() 38 | set(OVERLOOK_WITH_CXX FALSE) 39 | endif() 40 | 41 | # Project LANGUAGE not including C and CXX so we return 42 | if((NOT OVERLOOK_WITH_C) AND (NOT OVERLOOK_WITH_CXX)) 43 | message(WARNING "Neither C nor CXX compiler available. No OVERLOOK C/C++ flags will be set") 44 | message(WARNING "You may specify C and CXX in `project()` command") 45 | return() 46 | endif() 47 | 48 | # rule0: don't ignore all that warnings 49 | # If `-w` specified for GCC/Clang, report an error 50 | if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) 51 | get_directory_property(overlook_detected_global_compile_options COMPILE_OPTIONS) 52 | message("Detected Global Compile Options: ${overlook_detected_global_compile_options}") 53 | string(REGEX MATCH "-w" ignore_all_warnings "${overlook_detected_global_compile_options}" ) 54 | if(ignore_all_warnings) 55 | message(FATAL_ERROR "Found `-w` compile options, it ignore all warnings. Please remove it (in `add_compile_options)`") 56 | endif() 57 | endif() 58 | 59 | #-------------------------------------------------------------------------------- 60 | # Function return value related 61 | #-------------------------------------------------------------------------------- 62 | # rule1: calls a function when it is not declared. C compiler doesn't treat it an error, but we do. 63 | # 函数没有声明就使用, C编译器默认不报错,改为强制报错 64 | # 解决bug: 地址截断; 内存泄漏 65 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 66 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4013) 67 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4013) 68 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 69 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-function-declaration) 70 | if(CMAKE_CXX_COMPILER_VERSION LESS 9.1) 71 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-function-declaration) 72 | endif() 73 | if(CMAKE_C_COMPILER_VERSION GREATER_EQUAL 11.1) 74 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=builtin-declaration-mismatch) 75 | endif() 76 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 77 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-function-declaration) 78 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-function-declaration) 79 | endif() 80 | 81 | # rule2: 函数虽然有声明,但是声明不完整,没有写出返回值类型,C编译器默认不报错,改为强制报错 82 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 83 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4431) 84 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4431) 85 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 86 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-int) 87 | if(CMAKE_CXX_COMPILER_VERSION LESS 9.1) 88 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-int) 89 | endif() 90 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 91 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-int) 92 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-int) 93 | endif() 94 | 95 | # rule4: when missing return value for non-void function, C/C++ compiler treat it as UB and not report error, we treat it as error. 96 | # it may cause crash, or just return un-expected result, depends on the compiler and the code you write 97 | # 函数应该有返回值但没有 return 返回值,或不是所有路径都有返回值,C和C++编译器默认不报错,改为强制报错 98 | # 解决bug: lane detect; vpdt for循环无法跳出(android输出trap); lane calib库读取到随机值导致获取非法格式asvl, 开asan则表现为读取NULL指针 99 | # -O3时输出内容和其他优化等级不一样 (from 三老师) 100 | # android arm64 表现为 trap: https://zhuanlan.zhihu.com/p/587673235 101 | # centos 升级 GCC 遇到 SIGSEGV: https://ttf248.life/p/升级gcc版本导致程序崩溃代码不规范的隐患 102 | # https://pvs-studio.com/en/blog/posts/cpp/0917/ https://godbolt.org/z/dqqYqsj5E 103 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 104 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4716 /we4715) 105 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4716 /we4715) 106 | else() 107 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=return-type) 108 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=return-type) 109 | endif() 110 | 111 | # rule30: 所有的控件路径(if/else)必须都有返回值 112 | # NDK21 Clang / Linux Clang/GCC/G++ 默认都报 error 113 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 114 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4715) 115 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4715) 116 | endif() 117 | 118 | # rule6: 函数不应该返回局部变量的地址 119 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 120 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4172) 121 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4172) 122 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 123 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=return-local-addr) 124 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=return-local-addr) 125 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 126 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=return-stack-address) 127 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=return-stack-address) 128 | endif() 129 | 130 | #-------------------------------------------------------------------------------- 131 | # Function argument/parameter, type conversion/casting related 132 | #-------------------------------------------------------------------------------- 133 | 134 | # rule12: 函数声明中的参数列表和定义中不一样。在 MSVC C 下为警告, Linux Clang 下报错 135 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 136 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4029) 137 | endif() 138 | 139 | # rule13: 实参太多, 比函数定义或声明中的要多。只在MSVC C 下为警告, Linux Clang下报错 140 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 141 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4020) 142 | endif() 143 | 144 | # rule14: 避免 void* 类型的指针参参与算术运算 145 | # MSVC C/C++ 默认会报错, Linux gcc 不报 warning 和 error, Linux g++ 只报 warning 146 | # Linux 下 Clang 开 -Wpedentric 才报 warning, Clang++ 报 error 147 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 148 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=pointer-arith) 149 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=pointer-arith) 150 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 151 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=pointer-arith) 152 | endif() 153 | 154 | # rule3: 指针类型不兼容,C编译器默认不报错,改为强制报错 155 | # 解决bug: crash或结果异常 156 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 157 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4133) 158 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4133) 159 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 160 | if(CMAKE_CXX_COMPILER_VERSION GREATER 4.8) # gcc/g++ 4.8.3 not ok 161 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=incompatible-pointer-types) 162 | if(CMAKE_CXX_COMPILER_VERSION LESS 9.1) 163 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=incompatible-pointer-types) 164 | endif() 165 | endif() 166 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 167 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=incompatible-pointer-types) 168 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=incompatible-pointer-types) 169 | endif() 170 | 171 | # rule10: 避免把 int 指针赋值给 int 类型变量 172 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 173 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4047) 174 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4047) 175 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 176 | if(CMAKE_CXX_COMPILER_VERSION GREATER 4.8) 177 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=int-conversion) 178 | if(CMAKE_CXX_COMPILER_VERSION LESS 9.1) 179 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=int-conversion) 180 | endif() 181 | endif() 182 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 183 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=int-conversion) 184 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=int-conversion) 185 | endif() 186 | 187 | # rule8: printf 等语句中的格式串和实参类型不匹配,要避免 188 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 189 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4477) 190 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4477) 191 | else() 192 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=format) 193 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=format) 194 | endif() 195 | 196 | # rule17: 形参与声明不同。场景:静态库(.h/.c),集成时换库但没换头文件,且函数形参有变化(类型或数量) 197 | # 只报 warning 不报 error。仅 VS 出现 198 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 199 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4028) 200 | endif() 201 | 202 | # rule21: “类型强制转换”: 例如从 int 转换到更大的 void* 203 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 204 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4312) 205 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4312) 206 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 207 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=int-to-pointer-cast) 208 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=int-to-pointer-cast) 209 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 210 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=int-to-pointer-cast) 211 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=int-to-pointer-cast) 212 | endif() 213 | 214 | # rule23: 类函数宏的调用 参数过多 215 | # VC/VC++ 报警告。Linux 下的 GCC/Clang 报 error 216 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 217 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4002) 218 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4002) 219 | endif() 220 | 221 | # rule24: 类函数宏的调用 参数不足 222 | # VC/VC++ 同时会报 error C2059 223 | # Linux GCC/Clang 直接报错 224 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 225 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4003) 226 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4003) 227 | endif() 228 | 229 | #-------------------------------------------------------------------------------- 230 | # Initialization, memory release related 231 | #-------------------------------------------------------------------------------- 232 | 233 | # rule7: 变量没初始化就使用,要避免 234 | # if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 235 | # list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4700 /we26495) 236 | # list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4700 /we26495) 237 | # else() 238 | # list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=uninitialized) 239 | # list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=uninitialized) 240 | # endif() 241 | 242 | # rule11: 检查数组下标越界访问 243 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 244 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we6201 /we6386 /we4789) 245 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we6201 /we6386 /we4789) 246 | else() 247 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=array-bounds) 248 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=array-bounds) 249 | endif() 250 | 251 | # rule16: 释放非堆内存 252 | # TODO: 检查 MSVC 253 | # Linux Clang8.0 无法检测到 254 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 255 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=free-nonheap-object) 256 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=free-nonheap-object) 257 | endif() 258 | 259 | # rule32: 用 memset 等 C 函数设置 非 POD class 对象 260 | # Linux下, GCC9.3 能发现此问题, 但clang10 不能发现 261 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 262 | if(CMAKE_CXX_COMPILER_VERSION GREATER 7.5) 263 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=class-memaccess) 264 | endif() 265 | endif() 266 | 267 | # rule15: 避免符号重复定义(变量对应的强弱符号)。只在 C 中出现。 268 | # 暂时没找到 MSVC 的对应编译选项 269 | if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR CMAKE_C_COMPILER_ID MATCHES "Clang") 270 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -fno-common) 271 | endif() 272 | 273 | #-------------------------------------------------------------------------------- 274 | # Pre-compilation directive related 275 | #-------------------------------------------------------------------------------- 276 | 277 | # rule18: 宏定义重复 278 | # gcc5~gcc9 无法检查 279 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 280 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4005) 281 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4005) 282 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 283 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=macro-redefined) 284 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=macro-redefined) 285 | endif() 286 | 287 | # rule19: pragma init_seg 指定了非法(不能识别的)section名字 288 | # VC++ 特有。Linux 下的 gcc/clang 没有 289 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 290 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4075) 291 | endif() 292 | 293 | # rule25: #undef 没有跟一个标识符 294 | # Linux GCC/Clang 直接报错 295 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 296 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4006) 297 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4006) 298 | endif() 299 | 300 | 301 | #-------------------------------------------------------------------------------- 302 | # Unused stuffs related 303 | #-------------------------------------------------------------------------------- 304 | 305 | # rule27: 没有使用到表达式结果(无用代码行,应删除) 306 | # 感觉容易被误伤,可以考虑关掉 307 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 308 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4552 /we4555) 309 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4552 /we4555) 310 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 311 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=unused-value) 312 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=unused-value) 313 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 314 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=unused-value) 315 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=unused-value) 316 | endif() 317 | 318 | # rule28: “==”: 未使用表达式结果;是否打算使用“=”? 319 | # Linux GCC 没有对应的编译选项 320 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 321 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4553) 322 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4553) 323 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 324 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=unused-comparison) 325 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=unused-comparison) 326 | endif() 327 | 328 | # 可能会导致下一行代码报错,而问题根源在包含继续符的这行注释 329 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 330 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4006) 331 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4006) 332 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 333 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=comment) 334 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=comment) 335 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 336 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=comment) 337 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=comment) 338 | endif() 339 | 340 | 341 | #-------------------------------------------------------------------------------- 342 | # String/Char related 343 | #-------------------------------------------------------------------------------- 344 | 345 | # rule22: 不可识别的字符转义序列 346 | # GCC5.4 能显示 warning 但无别名,因而无法视为 error 347 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 348 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4129) 349 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4129) 350 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 351 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=unknown-escape-sequence) 352 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=unknown-escape-sequence) 353 | endif() 354 | 355 | # rule29: C++中,禁止把字符串常量赋值给 char* 变量 356 | # VS2019 开启 /Wall 后也查不到 357 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 358 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=write-strings) 359 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 360 | # Linux Clang 和 AppleClang 不太一样 361 | if(CMAKE_SYSTEM_NAME MATCHES "Linux") 362 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=writable-strings) 363 | elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") 364 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=c++11-compat-deprecated-writable-strings) 365 | endif() 366 | endif() 367 | 368 | # rule31: multi-char constant 369 | # MSVC 没有对应的选项 370 | if(CMAKE_C_COMPILER_ID STREQUAL "GNU") 371 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=multichar) 372 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=multichar) 373 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 374 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=multichar) 375 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=multichar) 376 | endif() 377 | 378 | #-------------------------------------------------------------------------------- 379 | # Type safe related 380 | #-------------------------------------------------------------------------------- 381 | # rule9: 避免把 unsigned int 和 int 直接比较 382 | # 通常会误伤,例如 for 循环中。可以考虑关掉 383 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 384 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4018) 385 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4018) 386 | elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU") 387 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=sign-compare) 388 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=sign-compare) 389 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 390 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=sign-compare) 391 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=sign-compare) 392 | endif() 393 | 394 | # rule20: size_t 类型被转为更窄类型 395 | # VC/VC++ 特有。 Linux 下的 gcc/clang 没有 396 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 397 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4267) 398 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4267) 399 | endif() 400 | 401 | ## rule34: double 型转 float 型,可能有精度丢失(尤其在 float 较大时) 402 | # MSVC 默认是放在 /W3 403 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 404 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we4244) 405 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4244) 406 | endif() 407 | 408 | ## rule37: float 转换隐式转换为 int,可能改变变量的值 409 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 410 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=float-conversion) 411 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 412 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=float-conversion) 413 | endif() 414 | 415 | 416 | #-------------------------------------------------------------------------------- 417 | # Misc 418 | #-------------------------------------------------------------------------------- 419 | 420 | ## rule33: 括号里面是单个等号而不是双等号 421 | # Linux Clang14 可以发现问题,但 GCC9.3 无法发现; android clang 可以发现 422 | if(CMAKE_C_COMPILER_ID MATCHES "Clang") 423 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=parentheses) 424 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=parentheses) 425 | endif() 426 | 427 | 428 | ## rule35: 父类有 virtual 的成员函数,但析构函数是 public 并且不是 virtual, 会导致 UB 429 | # https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c35-a-base-class-destructor-should-be-either-public-and-virtual-or-protected-and-non-virtual 430 | # -Wnon-virtual-dtor (C++ and Objective-C++ only) 431 | # Warn when a class has virtual functions and an accessible non-virtual destructor itself or in an accessible polymorphic base 432 | # class, in which case it is possible but unsafe to delete an instance of a derived class through a pointer to the class 433 | # itself or base class. This warning is automatically enabled if -Weffc++ is specified. 434 | if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 435 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=non-virtual-dtor) 436 | elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") 437 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=non-virtual-dtor) 438 | endif() 439 | 440 | ## rule36: switch case 忘记写 break, 会 fallthrough 执行, 可能导致数组越界(具体取决于你的代码). 不写break我们视为错误。 441 | if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) 442 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-fallthrough) 443 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-fallthrough) 444 | elseif((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) 445 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=implicit-fallthrough) 446 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=implicit-fallthrough) 447 | endif() 448 | 449 | ## rule37: 遇到第一个报错就停止编译 450 | if((CMAKE_C_COMPILER_ID STREQUAL "GNU") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")) 451 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Wfatal-errors) 452 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Wfatal-errors) 453 | elseif((CMAKE_C_COMPILER_ID MATCHES "Clang") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) 454 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Wfatal-errors) 455 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Wfatal-errors) 456 | endif() 457 | 458 | ## rule38: 函数承诺不抛异常, 但具体实现抛出了异常 459 | if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 460 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we4297) 461 | elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 462 | if(CMAKE_CXX_COMPILER_VERSION GREATER_EQUAL 11.3) 463 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=exceptions) 464 | endif() 465 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 466 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=exceptions) 467 | endif() 468 | 469 | ## rule39: using reserved identifiers is forbidden 470 | ## https://en.cppreference.com/w/cpp/language/identifiers 471 | if(CMAKE_C_COMPILER_ID MATCHES "Clang") 472 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=reserved-identifier) 473 | endif() 474 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 475 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=reserved-identifier) 476 | endif() 477 | 478 | 479 | # rule5: 避免使用影子(shadow)变量 480 | # 有时候会误伤, 例如eigen等开源项目, 可以手动关掉 481 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC") 482 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS /we6244 /we6246 /we4457 /we4456) 483 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS /we6244 /we6246 /we4457 /we4456) 484 | else() 485 | list(APPEND OVERLOOK_C_COMPILE_OPTIONS -Werror=shadow) 486 | list(APPEND OVERLOOK_CXX_COMPILE_OPTIONS -Werror=shadow) 487 | endif() 488 | 489 | 490 | # 将上述定制的 FLAGS 追加到 CMAKE 默认的编译选项中 491 | # 为什么是添加而不是直接设定呢?因为 xxx-toolchain.cmake 中可能会设置一些默认值 (如 Android NDK), 需要避免这些默认值被覆盖 492 | string(REPLACE ";" " " OVERLOOK_C_FLAGS "${OVERLOOK_C_COMPILE_OPTIONS}") 493 | string(REPLACE ";" " " OVERLOOK_CXX_FLAGS "${OVERLOOK_CXX_COMPILE_OPTIONS}") 494 | if(OVERLOOK_GLOBAL) 495 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OVERLOOK_C_FLAGS}") 496 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OVERLOOK_CXX_FLAGS}") 497 | else() 498 | add_library(overlook INTERFACE) 499 | target_compile_options(overlook INTERFACE $<$:${OVERLOOK_C_COMPILE_OPTIONS}>) 500 | target_compile_options(overlook INTERFACE $<$:${OVERLOOK_CXX_COMPILE_OPTIONS}>) 501 | endif() 502 | unset(OVERLOOK_C_COMPILE_OPTIONS) 503 | unset(OVERLOOK_CXX_COMPILE_OPTIONS) 504 | 505 | ################################################################################## 506 | # Add whole archive when build static library 507 | # Usage: 508 | # overlook_add_whole_archive_flag( ) 509 | # Example: 510 | # add_library(foo foo.hpp foo.cpp) 511 | # add_executable(bar bar.cpp) 512 | # overlook_add_whole_archive_flag(foo safe_foo) 513 | # target_link_libraries(bar ${safe_foo}) 514 | ################################################################################## 515 | function(overlook_add_whole_archive_flag lib output_var) 516 | if("${CMAKE_CXX_COMPILER_ID}" MATCHES "MSVC") 517 | if(MSVC_VERSION GREATER 1900) 518 | set(${output_var} -WHOLEARCHIVE:$ PARENT_SCOPE) 519 | else() 520 | message(WARNING "MSVC version is ${MSVC_VERSION}, /WHOLEARCHIVE flag cannot be set") 521 | set(${output_var} ${lib} PARENT_SCOPE) 522 | endif() 523 | elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") 524 | set(${output_var} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive PARENT_SCOPE) 525 | elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND CMAKE_SYSTEM_NAME MATCHES "Linux") 526 | # set(${output_var} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive PARENT_SCOPE) 527 | elseif("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" AND NOT ANDROID) 528 | set(${output_var} -Wl,-force_load ${lib} PARENT_SCOPE) 529 | elseif(ANDROID) 530 | # 即使是 NDK21 并且手动传入 ANDROID_LD=lld, 依然要用ld的查重复符号的链接选项 531 | set(${output_var} -Wl,--whole-archive ${lib} -Wl,--no-whole-archive PARENT_SCOPE) 532 | else() 533 | message(FATAL_ERROR "add_whole_archive_flag not supported yet for current compiler: ${CMAKE_CXX_COMPILER_ID}") 534 | endif() 535 | endfunction() 536 | 537 | 538 | -------------------------------------------------------------------------------- /plugins/overlook/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_overlook) 3 | 4 | set(CMAKE_CXX_STANDARD 11) 5 | message("CMAKE_C_COMPILER_ID: ${CMAKE_C_COMPILER_ID}") 6 | message("CMAKE_CXX_COMPILER_ID: ${CMAKE_CXX_COMPILER_ID}") 7 | include(../overlook.cmake) 8 | 9 | add_executable(test01 test01.c) 10 | add_executable(test02 test02.c) 11 | add_executable(test03 test03.c) 12 | add_subdirectory(test04 test04) 13 | add_executable(test05 test05.cpp) 14 | add_executable(test06 test06.cpp) 15 | add_executable(test07 test07.cpp) 16 | add_executable(test08 test08.cpp) 17 | add_executable(test09 test09.cpp) 18 | add_executable(test10 test10.c) 19 | add_executable(test11 test11.cpp) 20 | add_executable(test12 test12.c) 21 | add_executable(test13 test13.c) 22 | add_executable(test14 test14.c) 23 | add_subdirectory(test15 test15) 24 | add_executable(test16 test16.cpp) 25 | add_subdirectory(test17 test17) 26 | add_executable(test18 test18.cpp) 27 | add_executable(test19 test19.cpp) 28 | add_executable(test20 test20.cpp) 29 | add_executable(test21 test21.cpp) 30 | add_executable(test22 test22.cpp) 31 | add_executable(test23 test23.cpp) 32 | add_executable(test24 test24.cpp) 33 | add_executable(test25 test25.cpp) 34 | add_executable(test26 test26.cpp) 35 | add_executable(test27 test27.cpp) 36 | add_executable(test28 test28.cpp) 37 | add_executable(test29 test29.cpp) 38 | add_executable(test30 test30.cpp) 39 | add_subdirectory(test31 test31) 40 | add_executable(test32 test32.cpp) 41 | add_executable(test33 test33.cpp) 42 | add_executable(test34 test34.cpp) 43 | add_executable(test35 test35.cpp) 44 | add_executable(test36 test36.cpp) 45 | add_executable(test37 test37.cpp) 46 | add_executable(test38 test38.cpp) 47 | add_executable(test39 test39.cpp) 48 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test01.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | // 函数没有声明返回类型 5 | add(int a, int b) 6 | { 7 | return a + b; 8 | } 9 | 10 | int test() 11 | { 12 | int a = 0; 13 | int b = 0; 14 | int c = 0; 15 | int d = 0; 16 | 17 | c = add(a, b); 18 | return 0; 19 | } 20 | 21 | int main() 22 | { 23 | printf("hello cmake\n"); 24 | 25 | int* data = (int*)malloc(100 * sizeof(int)); /* missing #include */ 26 | data[0] = 233; 27 | 28 | test(); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test02.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // 函数没有声明返回类型 4 | add(int a, int b) 5 | { 6 | return a + b; 7 | } 8 | 9 | int test() 10 | { 11 | int a = 0; 12 | int b = 0; 13 | int c = 0; 14 | int d = 0; 15 | 16 | c = add(a, b); 17 | return 0; 18 | } 19 | 20 | int main() 21 | { 22 | test(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test03.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print_data(int* data, int len) 4 | { 5 | for (int i = 0; i < len; i++) 6 | { 7 | printf("%d ", data[i]); 8 | } 9 | printf("\n"); 10 | } 11 | 12 | int main() 13 | { 14 | unsigned char data[10]; 15 | for (int i = 0; i < 10; i++) 16 | { 17 | data[i] = i; 18 | } 19 | print_data(data, 10); 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test4 2 | ${CMAKE_CURRENT_SOURCE_DIR}/main.c 3 | ) -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/README.md: -------------------------------------------------------------------------------- 1 | # Analysis of missing return value for non-void function 2 | 3 | - [analysis of Linux Clang compiler](analysis-clang.md) 4 | - [analysis of Linux GCC compiler](analysis-gcc.md) 5 | - [analysis of MSVC compiler](analysis-msvc.md) 6 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/analysis-clang.md: -------------------------------------------------------------------------------- 1 | # Analysis of missing return value for non-void function, Clang compiler 2 | 3 | ## Preparation 4 | Let's analysis why there is "crash" when missing return value for non-void function. 5 | - OS: ubuntu 22.04 6 | - Compiler: Clang 15.0.7 7 | - Code: based on main.cpp 8 | - Analysis method: 9 | - build and run main.cpp twice, first is missing return, second is with return 10 | - compare disassembly code 11 | - Conclusion: 12 | - an `ud2` instruction is generated and being executed. 13 | 14 | ## First run 15 | ```cpp 16 | #include 17 | 18 | int print_data(int* data, int len) 19 | { 20 | for (int i = 0; i < len; i++) 21 | { 22 | printf("%d ", data[i]); 23 | } 24 | printf("\n"); 25 | // here the return value is missing 26 | } 27 | ``` 28 | 29 | ```bash 30 | clang++ main.cpp 31 | objdump -d a.out > 1.txt 32 | ``` 33 | 34 | ## Second run 35 | ```cpp 36 | #include 37 | 38 | int print_data(int* data, int len) 39 | { 40 | for (int i = 0; i < len; i++) 41 | { 42 | printf("%d ", data[i]); 43 | } 44 | printf("\n"); 45 | return 233; // here we add return statement 46 | } 47 | ``` 48 | 49 | ```bash 50 | clang++ main.cpp 51 | objdump -d a.out > 2.txt 52 | ``` 53 | 54 | ## Disassembly and compare 55 | 56 | ![](cpp_clang16_disassembly_compare.webp) 57 | 58 | We see function epilogue is missing when missing return statement (1.txt, the left part of the image). 59 | 60 | The prologue and epilogue for a function should match, i.e. "keep balanced stack". 61 | 62 | The function prologue is: 63 | ```asm 64 | 1140: 55 push %rbp 65 | 1141: 48 89 e5 mov %rsp,%rbp 66 | 1144: 48 83 ec 10 sub $0x10,%rsp 67 | ``` 68 | which decrease the stack by 16 (`sub $0x10, %rsp`), the expected function epilogue should add it back. 69 | 70 | ## Use LLDB with disassembly 71 | ```bash 72 | clang++ main.cpp -g 73 | ``` 74 | The `-g` keeps debug symbols, which contains source code line number. 75 | 76 | The key commands that I use in LLDB: 77 | - `si`: step into next instruction 78 | - `dis`: disassembly 79 | 80 | ![](lldb_disassembly1.webp) 81 | 82 | ![](lldb_disassembly2.webp) 83 | 84 | After executing calling printf by `call 0x555555555030`, we still execute `si`, which executes `ud2`. 85 | **ud2** means "Raise invalid opcode exception": 86 | - https://www.felixcloutier.com/x86/ud 87 | - https://learn.microsoft.com/en-us/cpp/intrinsics/ud2?view=msvc-170#:~:text=Generates%20an%20undefined%20instruction.%20Syntax%20C%20void%20__ud2,function%20is%20equivalent%20to%20the%20UD2%20machine%20instruction. 88 | 89 | 90 | ```lldb 91 | 0x555555555190 <+80>: mov al, 0x0 92 | -> 0x555555555192 <+82>: call 0x555555555030 ; symbol stub for: printf 93 | 0x555555555197 <+87>: ud2 94 | (lldb) si 95 | Process 957585 stopped 96 | * thread #1, name = 'a.out', stop reason = instruction step into 97 | frame #0: 0x0000555555555030 a.out`printf 98 | a.out`printf: 99 | -> 0x555555555030 <+0>: jmp qword ptr [rip + 0x2fe2] ; _GLOBAL_OFFSET_TABLE_ + 24 100 | 0x555555555036 <+6>: push 0x0 101 | 0x55555555503b <+11>: jmp 0x555555555020 ; ___lldb_unnamed_symbol43 102 | 103 | a.out`___lldb_unnamed_symbol44: 104 | 0x555555555040 <+0>: jmp qword ptr [rip + 0x2f92] 105 | ``` -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/analysis-gcc.md: -------------------------------------------------------------------------------- 1 | # Analysis of missing return value for non-void function, GCC compiler 2 | 3 | ## Preparation 4 | - The code and compiler information can be obtained in: https://godbolt.org/z/1GdKb7dc9 5 | - gcc version 13.2 6 | - analysis method: 7 | - run the code, found there's no crash, but result is "tricky" 8 | - observe `eax` register for function return value 9 | - conclusion 10 | - the `hello()` function makes the `eax` register stores `233` 11 | - the `print_data()` function 12 | 13 | ## Code 14 | `main.c` (instead of cpp file): 15 | ```cpp 16 | #include 17 | 18 | int hello() 19 | { 20 | return 233; 21 | } 22 | 23 | int print_data(int* data, int len) 24 | { 25 | for (int i = 0; i < len; i++) 26 | { 27 | printf("%d ", data[i]); 28 | } 29 | printf("\n"); 30 | hello(); 31 | } 32 | 33 | void example1() 34 | { 35 | int data[10]; 36 | for (int i = 0; i < 10; i++) 37 | { 38 | data[i] = i; 39 | } 40 | int res = print_data(data, 10); 41 | 42 | printf("res=%d\n", res); 43 | } 44 | 45 | int main() 46 | { 47 | example1(); 48 | //example2(); 49 | 50 | return 0; 51 | } 52 | ``` 53 | 54 | 55 | ## Execution result 56 | ``` 57 | ASM generation compiler returned: 0 58 | Execution build compiler returned: 0 59 | Program returned: 0 60 | 0 1 2 3 4 5 6 7 8 9 61 | res=233 62 | ``` 63 | 64 | ## Analysis 65 | The disassemble code of `print_data()` is: 66 | ```asm 67 | print_data: 68 | push rbp 69 | mov rbp,rsp 70 | sub rsp,0x20 71 | mov QWORD PTR [rbp-0x18],rdi 72 | mov DWORD PTR [rbp-0x1c],esi 73 | mov DWORD PTR [rbp-0x4],0x0 74 | jmp 401184 75 | mov eax,DWORD PTR [rbp-0x4] 76 | cdqe 77 | lea rdx,[rax*4+0x0] 78 | mov rax,QWORD PTR [rbp-0x18] 79 | add rax,rdx 80 | mov eax,DWORD PTR [rax] 81 | mov esi,eax 82 | mov edi,0x402004 83 | mov eax,0x0 84 | call 401040 85 | add DWORD PTR [rbp-0x4],0x1 86 | mov eax,DWORD PTR [rbp-0x4] 87 | cmp eax,DWORD PTR [rbp-0x1c] 88 | jl 401159 89 | mov edi,0xa 90 | call 401030 91 | mov eax,0x0 92 | call 401136 93 | nop 94 | leave 95 | ret 96 | ``` 97 | 98 | After calling `hello()`, the `eax` register is with value `233`. 99 | (Note the `leave` is the function epilogue, hence the stack is balanced, ref: https://handwiki.org/wiki/Function_prologue_and_epilogue) -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/analysis-msvc.md: -------------------------------------------------------------------------------- 1 | # Analysis of missing return value for non-void function, MSVC 2 | 3 | First, rename main.cpp to main.c, and modify CMakeLists.txt. 4 | 5 | ## Debug build type result 6 | In VS2022-x64 Debug build type, the running result is: 7 | ``` 8 | 0 1 2 3 4 5 6 7 8 9 9 | res=233 10 | ``` 11 | 12 | ![](vs2022-x64-Debug.png) 13 | 14 | `res=233` is due to `hello()` returns 233. 15 | 16 | ## RelWithDebInfo build type result 17 | ``` 18 | 0 1 2 3 4 5 6 7 8 9 19 | res=1 20 | ``` 21 | 22 | ![](vs2022-x64-RelWithDebInfo.png) 23 | 24 | `res=1` is due to `printf()` returns 1. The `hello()` is not called due to optimization. 25 | 26 | ## Corresponding code: 27 | ```c 28 | #include 29 | 30 | int hello() 31 | { 32 | return 233; 33 | } 34 | 35 | int print_data(int* data, int len) 36 | { 37 | for (int i = 0; i < len; i++) 38 | { 39 | printf("%d ", data[i]); 40 | } 41 | printf("\n"); 42 | // hello(); 43 | } 44 | 45 | void example1() 46 | { 47 | int data[10]; 48 | for (int i = 0; i < 10; i++) 49 | { 50 | data[i] = i; 51 | } 52 | int res = print_data(data, 10); 53 | 54 | printf("res = %d\n", res); 55 | } 56 | 57 | int main() 58 | { 59 | example1(); 60 | 61 | return 0; 62 | } 63 | 64 | ``` 65 | 66 | 67 | ## Pure-command-line 68 | Enter x64 Native Tools Command Prompt windows, 69 | 70 | ```bash 71 | cd build 72 | dumpbin /DISASM RelWithDebInfo\test_rule4.exe > 1.asm 73 | ``` 74 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/cpp_clang15_disassembly_compare.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zchrissirhcz/rocbuild/930fedd266e64c87b072c39fd66b97316e6939e1/plugins/overlook/tests/test04/cpp_clang15_disassembly_compare.webp -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/lldb_disassembly1.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zchrissirhcz/rocbuild/930fedd266e64c87b072c39fd66b97316e6939e1/plugins/overlook/tests/test04/lldb_disassembly1.webp -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/lldb_disassembly2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zchrissirhcz/rocbuild/930fedd266e64c87b072c39fd66b97316e6939e1/plugins/overlook/tests/test04/lldb_disassembly2.webp -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int hello() 4 | { 5 | return 233; 6 | } 7 | 8 | int print_data(int* data, int len) 9 | { 10 | for (int i = 0; i < len; i++) 11 | { 12 | printf("%d ", data[i]); 13 | } 14 | printf("\n"); 15 | // here the return statement is missing, the compiler will generate an UB 16 | hello(); 17 | } 18 | 19 | void example1() 20 | { 21 | int data[10]; 22 | for (int i = 0; i < 10; i++) 23 | { 24 | data[i] = i; 25 | } 26 | int res = print_data(data, 10); 27 | 28 | printf("res=%d\n", res); 29 | } 30 | 31 | //--------------------- 32 | 33 | int func1(int i) 34 | { 35 | if (i) 36 | return 3; // C4715 warning, nothing returned if i == 0 37 | } 38 | 39 | void fatal() 40 | { 41 | } 42 | int glue() 43 | { 44 | if (0) 45 | return 1; 46 | else if (0) 47 | return 0; 48 | else 49 | fatal(); // C4715 50 | } 51 | 52 | void example2() 53 | { 54 | func1(233); 55 | int qaq = glue(); 56 | printf("%d\n", qaq); 57 | } 58 | 59 | //----------------------------- 60 | 61 | int main() 62 | { 63 | example1(); 64 | //example2(); 65 | 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/vs2022-x64-Debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zchrissirhcz/rocbuild/930fedd266e64c87b072c39fd66b97316e6939e1/plugins/overlook/tests/test04/vs2022-x64-Debug.png -------------------------------------------------------------------------------- /plugins/overlook/tests/test04/vs2022-x64-RelWithDebInfo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zchrissirhcz/rocbuild/930fedd266e64c87b072c39fd66b97316e6939e1/plugins/overlook/tests/test04/vs2022-x64-RelWithDebInfo.png -------------------------------------------------------------------------------- /plugins/overlook/tests/test05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int len = 100; 6 | for (int i = 0; i < 10; i++) 7 | { 8 | int len = 10; 9 | printf("process %d/%d\n", i, len); 10 | } 11 | 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test06.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int* get_lucky_number() 4 | { 5 | int data = 10; 6 | return &data; 7 | } 8 | 9 | int return_stack_addr() 10 | { 11 | int* lucky_number = get_lucky_number(); 12 | printf("lucky number is %d\n", *lucky_number); 13 | 14 | return 0; 15 | } 16 | 17 | 18 | #include 19 | #include 20 | 21 | std::string& f() 22 | { 23 | std::string s = "Example"; 24 | return s; // exits the scope of s: 25 | // its destructor is called and its storage deallocated 26 | } 27 | 28 | int dangling_reference() 29 | { 30 | std::string& r = f(); // dangling reference 31 | std::cout << r; // undefined behavior: reads from a dangling reference 32 | std::string s = f(); // undefined behavior: copy-initializes from a dangling reference 33 | std::cout << s << std::endl; 34 | return 0; 35 | } 36 | 37 | 38 | int main(int argc, char** /*argv*/) 39 | { 40 | return_stack_addr(); 41 | dangling_reference(); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test07.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int read_of_unitialized() 4 | { 5 | int data; // garbage value 6 | 7 | if (data > 10) 8 | { 9 | printf("data > 10\n"); 10 | } 11 | else 12 | { 13 | printf("data <= 10\n"); 14 | } 15 | 16 | int* ptr; 17 | printf("*ptr = %d\n", *ptr); 18 | 19 | return 0; 20 | } 21 | 22 | __attribute__((noinline)) 23 | int bar(int n) 24 | { 25 | return n * n; 26 | } 27 | 28 | __attribute__((noinline)) 29 | int foo(const int *p) 30 | { 31 | int n; 32 | 33 | if (p) 34 | n = p[0]; 35 | return bar(n); 36 | } 37 | 38 | // https://zhuanlan.zhihu.com/p/1891261469053671394 39 | // segmentation fault 40 | int write_of_unitlialized() 41 | { 42 | foo(0); 43 | return 0; 44 | } 45 | 46 | int main() 47 | { 48 | // read_of_unitialized(); 49 | write_of_unitlialized(); 50 | 51 | return 0; 52 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test08.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int len = 100; 6 | printf("len = %lf\n", len); 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test09.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() 8 | { 9 | vector data; 10 | data.push_back(1); 11 | data.push_back(2); 12 | data.push_back(3); 13 | 14 | for (int i = 0; i < data.size(); i++) 15 | { 16 | printf("data[%d]=%d\n", i, data[i]); 17 | } 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test10.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int data = 10; 6 | int* ptr = &data; 7 | 8 | int addr = ptr; 9 | printf("add is %d\n", addr); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | //(1) 6 | #ifdef __cplusplus 7 | const int maxn = 10; 8 | int a[maxn]; 9 | a[10] = 1; 10 | #endif 11 | 12 | //(2) 13 | #define MAX 25 14 | int ar[MAX]; 15 | ar[MAX] = 1; 16 | 17 | //(3) 18 | int buff[25]; 19 | for (int i = 0; i <= 25; i++) // i exceeds array bound 20 | { 21 | buff[i] = 0; // initialize i 22 | //if (i == 1) { /* Do something */ } 23 | } 24 | 25 | //(4) 26 | int data[10]; 27 | data[10] = 233; 28 | printf("data[10]=%d\n", data[10]); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test12.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print_data(int* data, int len); 4 | 5 | void print_data(int* data, size_t len) 6 | { 7 | for (size_t i = 0; i < len; i++) 8 | { 9 | printf("%d\n", data[i]); 10 | } 11 | } 12 | 13 | int main() 14 | { 15 | int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 16 | print_data(data, 10); 17 | 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test13.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void print_data(int* data, size_t len) 4 | { 5 | for (size_t i = 0; i < len; i++) 6 | { 7 | printf("%d\n", data[i]); 8 | } 9 | } 10 | 11 | int main() 12 | { 13 | int data[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 14 | print_data(data, 10, 233); 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test14.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int* data = (int*)malloc(sizeof(int) * 10); 7 | for (int i = 0; i < 10; i++) 8 | { 9 | data[i] = i; 10 | } 11 | void* p = data; 12 | p += 5; 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test15/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test15 2 | ${CMAKE_CURRENT_SOURCE_DIR}/a.c 3 | ${CMAKE_CURRENT_SOURCE_DIR}/b.c 4 | ) -------------------------------------------------------------------------------- /plugins/overlook/tests/test15/README.md: -------------------------------------------------------------------------------- 1 | ref: https://cloud.tencent.com/developer/article/1673168 -------------------------------------------------------------------------------- /plugins/overlook/tests/test15/a.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int x = 7; 4 | int y = 5; 5 | 6 | void p1() 7 | { 8 | } 9 | 10 | void p2(); 11 | 12 | int main() 13 | { 14 | p2(); 15 | 16 | printf("y=%d\n", y); 17 | 18 | return 0; 19 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test15/b.c: -------------------------------------------------------------------------------- 1 | double x; 2 | 3 | void p2() 4 | { 5 | x = 10; 6 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | int data[5]; 7 | for (int i = 0; i < 5; i++) 8 | { 9 | data[i] = i; 10 | } 11 | free(data); 12 | 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #--------------------------------- 2 | # 原来版本的hello库,源码放在old目录 3 | #--------------------------------- 4 | if(0) 5 | add_library(hello STATIC 6 | ${CMAKE_CURRENT_SOURCE_DIR}/old/hello.h 7 | ${CMAKE_CURRENT_SOURCE_DIR}/old/hello.c 8 | ) 9 | endif() 10 | 11 | #--------------------------------- 12 | # 新版本的hello库,源码放在new目录 13 | #--------------------------------- 14 | if(1) 15 | add_library(hello STATIC 16 | ${CMAKE_CURRENT_SOURCE_DIR}/new/hello.h 17 | ${CMAKE_CURRENT_SOURCE_DIR}/new/hello.c 18 | ) 19 | endif() 20 | 21 | #--------------------------------- 22 | # 新版本的hello库,源码放在new目录 23 | #--------------------------------- 24 | add_executable(test17 25 | ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp 26 | ) 27 | # 以为hello库的头文件没有换过,一直用old目录里的hello.h 28 | target_include_directories(test17 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/old) 29 | target_link_libraries(test17 hello) -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/README.md: -------------------------------------------------------------------------------- 1 | 用new目录(模拟新版的hello)的代码编译出库,但testcase用的hello的头文件是old目录的(模拟老版本的hello)。 2 | 3 | 模拟的是“库开发者修改了hello库的接口和源码,但调用者以为接口没变只变了库”的场景。 4 | 5 | 执行,发现什么都没输出。原因是,main.cpp中调用`hello()`的参数,不符合新库里面函数符号对应函数实现的参数列表。 6 | 7 | clang(或Xcode)里暂时不知道怎么报出错误来。 -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/main.cpp: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | #include 3 | 4 | int main() 5 | { 6 | hello(NULL); 7 | hello("Chris"); 8 | 9 | return 0; 10 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/new/hello.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | 3 | #include 4 | 5 | void hello(const char* name, int repeat) 6 | { 7 | for (int i = 0; i < repeat; i++) 8 | { 9 | if (name == NULL) 10 | { 11 | printf("hello world\n"); 12 | } 13 | else 14 | { 15 | printf("hello, %s\n", name); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/new/hello.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTCASE18_HELLO_H 2 | #define TESTCASE18_HELLO_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void hello(const char* name, int repeat); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/old/hello.c: -------------------------------------------------------------------------------- 1 | #include "hello.h" 2 | 3 | #include 4 | 5 | void hello(const char* name) 6 | { 7 | if (name == NULL) 8 | { 9 | printf("hello world\n"); 10 | } 11 | else 12 | { 13 | printf("hello, %s\n", name); 14 | } 15 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test17/old/hello.h: -------------------------------------------------------------------------------- 1 | #ifndef TESTCASE18_HELLO_H 2 | #define TESTCASE18_HELLO_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void hello(const char* name); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test18.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | #define TEST "test1" 5 | #define TEST "test2" // C4005 delete or rename to resolve the warning 6 | 7 | int main() 8 | { 9 | cout << TEST << endl; 10 | } 11 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test19.cpp: -------------------------------------------------------------------------------- 1 | //https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4075?view=msvc-160 2 | 3 | // C4075.cpp 4 | // compile with: /W1 5 | #pragma init_seg("mysegg") // C4075 6 | 7 | // try.. 8 | // #pragma init_seg(user) 9 | 10 | // https://stackoverflow.com/a/10199440/2999096 11 | 12 | // ``` 13 | // #pragma init_seg 14 | // ``` 15 | // 是VC++特有的 16 | 17 | // g++不能用,但有个类似的: 18 | // ``` 19 | // Some_Class A __attribute__ ((init_priority (2000))); 20 | // Some_Class B __attribute__ ((init_priority (543))); 21 | // ``` 22 | 23 | 24 | int main() 25 | { 26 | return 0; 27 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test20.cpp: -------------------------------------------------------------------------------- 1 | // C4267.cpp 2 | // compile by using: cl /W4 C4267.cpp 3 | 4 | #include 5 | 6 | void Func1(short) 7 | { 8 | } 9 | void Func2(int) 10 | { 11 | } 12 | void Func3(long) 13 | { 14 | } 15 | void Func4(size_t) 16 | { 17 | } 18 | 19 | int main() 20 | { 21 | size_t bufferSize = 10; 22 | Func1(bufferSize); // C4267 for all platforms 23 | Func2(bufferSize); // C4267 only for 64-bit platforms 24 | Func3(bufferSize); // C4267 only for 64-bit platforms 25 | Func4(bufferSize); // OK for all platforms 26 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // C4312.cpp 4 | // compile by using: cl /W1 /LD C4312.cpp 5 | void* f(int i) 6 | { 7 | return (void*)i; // C4312 for 64-bit targets 8 | } 9 | 10 | void* f2(long long i) 11 | { 12 | return (void*)i; // OK 13 | } 14 | 15 | int main() 16 | { 17 | int* data = (int*)f(10); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test22.cpp: -------------------------------------------------------------------------------- 1 | // C4129.cpp 2 | // compile with: /W1 3 | 4 | #include 5 | 6 | int main() 7 | { 8 | //char array1[] = "\/709"; // C4129 9 | char array2[] = "\n709"; // OK 10 | 11 | std::cout << "Default arguments: 1 I:\datasets\ADAS\adas_pcbt_test_20190403\images\list_imgtxt" << std::endl; 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test23.cpp: -------------------------------------------------------------------------------- 1 | // C4002.cpp 2 | // compile with: /W1 3 | #define test(a) (a) 4 | 5 | int main() 6 | { 7 | int a = 1; 8 | int b = 2; 9 | a = test(a, b); // C4002 10 | // try.. 11 | a = test(a); 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test24.cpp: -------------------------------------------------------------------------------- 1 | // C4003.cpp 2 | // compile with: /WX 3 | #define test(a, b) (a + b) 4 | 5 | int main() 6 | { 7 | int a = 1; 8 | int b = 2; 9 | a = test(b); // C4003 10 | // try.. 11 | a = test(a, b); 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test25.cpp: -------------------------------------------------------------------------------- 1 | // C4006.cpp 2 | // compile with: /W1 3 | #undef // C4006 4 | 5 | // try.. 6 | // #undef TEST 7 | 8 | int main() 9 | { 10 | return 0; 11 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test26.cpp: -------------------------------------------------------------------------------- 1 | // C4010.cpp 2 | // compile with: /WX 3 | int main() 4 | { 5 | // the next line is also a comment because of the backslash \ 6 | int a = 3; // C4010 7 | a++; 8 | 9 | return 0; 10 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/test27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void func1() 4 | { 5 | 1; // C4555 6 | } 7 | 8 | void func2() 9 | { 10 | int x; 11 | x; // C4555 12 | } 13 | 14 | void example1() 15 | { 16 | func1(); 17 | func2(); 18 | } 19 | 20 | void example2() 21 | { 22 | int i = 0, j = 0; 23 | i + j; // C4552 24 | // try the following line instead 25 | // (i + j); 26 | 27 | int k = 233; 28 | } 29 | 30 | 31 | bool master_is_working = false; 32 | void example3() 33 | { 34 | auto f = []() 35 | { 36 | !master_is_working; // C4552 37 | }; 38 | 39 | f(); 40 | std::cout << std::boolalpha << master_is_working << std::endl; 41 | // expected output: true 42 | // actual output: true 43 | // this examples is taken from 程序员还需要理解汇编吗? - 光度的回答 - 知乎 44 | // https://www.zhihu.com/question/609318862/answer/3115910062 45 | } 46 | 47 | int main() 48 | { 49 | example1(); 50 | example2(); 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test28.cpp: -------------------------------------------------------------------------------- 1 | // C4553.cpp 2 | // compile with: /W1 3 | int func() 4 | { 5 | return 0; 6 | } 7 | 8 | int main() 9 | { 10 | int i = 233; 11 | i == func(); // C4553 12 | // try the following line instead 13 | // i = func(); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test29.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void hello(char* data) 4 | { 5 | if (data) 6 | { 7 | printf("%s\n", data); 8 | } 9 | else 10 | { 11 | printf("hello world\n"); 12 | } 13 | } 14 | 15 | int main() 16 | { 17 | char* data1 = "hello cmake"; 18 | int size1 = sizeof(data1); 19 | printf("sizeof(data1)=%d\n", size1); // 输出的是sizeof(char*)的长度 20 | hello(data1); // 能正常执行并且输出 "hello cmake",但若hello函数内要用sizeof(data1),容易出错 21 | 22 | char data2[] = { "hello cmake" }; 23 | int size2 = sizeof(data2); 24 | printf("sizeof(data2)=%d\n", size2); // 输出的是sizeof(data2)的长度,包括了\0在内 25 | hello(data2); // 能正常执行并且输出 "hello cmake",而若hello函数内要用sizeof(data2),则能算对 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test30.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int reflect101_clip(int ti, int size) 4 | { 5 | if (ti < 0) 6 | { 7 | return -ti; 8 | } 9 | else if (ti > size - 1) 10 | { 11 | return 2 * size - 2 - ti; // size-1 - (ti-(size-1)) => size - 1 - (ti - size + 1) => size - 1 - ti + size - 1 => 2*size - 2 - ti 12 | } 13 | // 这里忘记 ti 在正常范围的情况下的返回值 14 | //else { 15 | // return ti; 16 | //} 17 | } 18 | 19 | int main() 20 | { 21 | printf("hello cmake\n"); 22 | int ti = 20; 23 | int size = 100; 24 | int new_ti = reflect101_clip(20, size); 25 | printf("ti=%d, reflect101_clip(ti,%d)=%d\n", ti, size, new_ti); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test31/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(test31 2 | ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp 3 | ) -------------------------------------------------------------------------------- /plugins/overlook/tests/test31/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Array 4 | { 5 | public: 6 | Array(int _len) 7 | : len(_len) 8 | { 9 | data = new double[len]; 10 | for (int i = 0; i < len; i++) 11 | { 12 | data[i] = 0; 13 | printf("data[%d]=%f\n", i, data[i]); 14 | } 15 | } 16 | 17 | friend std::ostream& operator<<(std::ostream& os, const Array& arr); 18 | 19 | public: 20 | int len; 21 | double* data; 22 | }; 23 | 24 | std::ostream& operator<<(std::ostream& os, const Array& arr) 25 | { 26 | for (int i = 0; i < arr.len; i++) 27 | { 28 | if (i > 0) 29 | { 30 | os << ', '; // 这里,导致输出的值,从第二个开始,原本是0而输出不为0 31 | } 32 | os << arr.data[i] << '\n'; 33 | } 34 | os << '\n'; 35 | return os; 36 | } 37 | 38 | void test_array() 39 | { 40 | Array arr(4); 41 | std::cout << arr << std::endl; 42 | } 43 | 44 | int main() 45 | { 46 | test_array(); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test31/test.c: -------------------------------------------------------------------------------- 1 | int main() 2 | { 3 | char c = ', '; 4 | return 0; 5 | } 6 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test32.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | class SmartPhone 7 | { 8 | int price; 9 | std::string name; 10 | }; 11 | 12 | int main() 13 | { 14 | printf("hello cmake\n"); 15 | 16 | SmartPhone* sp = (SmartPhone*)malloc(sizeof(SmartPhone)); 17 | memset(sp, 0, sizeof(*sp)); 18 | 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test33.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int a = 3; 6 | 7 | if (a == 1) 8 | { 9 | printf("1\n"); 10 | } 11 | else if (a = 2) // people careless write this, if not notice linter (e.g. Intellisense, Clangd), this only lead to compile warn for first time compile, later no warning 12 | { 13 | printf("2\n"); 14 | } 15 | else if (a == 3) 16 | { 17 | printf("3\n"); 18 | } 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test34.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | double a = 123.456; 6 | float b = a; 7 | printf("a = %lf\n", a); 8 | printf("b = %f\n", b); 9 | 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class Entity 4 | { 5 | public: 6 | Entity() 7 | { 8 | printf("Entity ctor()\n"); 9 | } 10 | ~Entity() 11 | { 12 | printf("Entity dtor()\n"); 13 | } 14 | 15 | virtual void hello() const 16 | { 17 | printf("Entity::hello()\n"); 18 | } 19 | }; 20 | 21 | class SubEntity : public Entity 22 | { 23 | public: 24 | void hello() const 25 | { 26 | printf("SubEntity::hello()\n"); 27 | } 28 | SubEntity() 29 | { 30 | printf("SubEntity ctor()\n"); 31 | } 32 | ~SubEntity() 33 | { 34 | printf("SubEntity dtor()\n"); 35 | } 36 | }; 37 | 38 | int main() 39 | { 40 | printf("hello cmake\n"); 41 | 42 | // SubEntity entity; 43 | // entity.hello(); 44 | 45 | Entity* p = new SubEntity; 46 | p->hello(); 47 | delete p; // 实际上,如果(在Linux)开启了 clangd, 例如 VSCode + clangd 插件, 会直接提示为下划波浪线 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test36.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | int data[4]; 6 | // there is `break` missing. It will run fallthrough 7 | int a = 0; 8 | switch (a) 9 | { 10 | case 0: 11 | printf("0\n"); 12 | data[a] = 233; 13 | case 1: 14 | printf("1\n"); 15 | data[a-1] = 233; 16 | case 2: 17 | printf("2\n"); 18 | data[a-2] = 233; 19 | case 3: 20 | printf("3\n"); 21 | data[a-3] = 233; 22 | break; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | float a = 0.5f; 7 | float b = std::abs(a); 8 | std::cout << b << std::endl; 9 | 10 | float c = ::abs(a); // note here: it's proto is: `int abs(int num)` 11 | std::cout << c << std::endl; 12 | 13 | float d = 3.14; // note here: double to float conversion happens 14 | std::cout << d << std::endl; 15 | 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test38.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //void recoup(int n) throw() 4 | void recoup(int n) noexcept 5 | { 6 | if (n == 0) 7 | throw std::invalid_argument("cannot be 0"); 8 | printf("valid: %d\n", n); 9 | } 10 | 11 | int main() 12 | { 13 | recoup(0); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /plugins/overlook/tests/test39.cpp: -------------------------------------------------------------------------------- 1 | #define _ENABLE_TEST 1 2 | 3 | int _Count; 4 | 5 | int _monster; 6 | 7 | int main() 8 | { 9 | int hello__world; 10 | int _Kali; 11 | 12 | int _yes; 13 | 14 | return 0; 15 | } -------------------------------------------------------------------------------- /plugins/overlook/tests/testX/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(testcaseX) 3 | include("../../overlook.cmake") 4 | add_executable(testcaseX 5 | ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp 6 | ) -------------------------------------------------------------------------------- /plugins/overlook/tests/testX/README.md: -------------------------------------------------------------------------------- 1 | 来自 卷卷群 的 小fufu 提供的样例代码。 2 | 3 | 试了VS2019-x64 /Wall,检测不出来。 4 | 试了LLVM-11.0,-Wall -Wpedantic -Wextra,检测不出来。 5 | 6 | 7 | 大缺弦说 这个实现是错误的。 -------------------------------------------------------------------------------- /plugins/overlook/tests/testX/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | class A 8 | { 9 | public: 10 | A() 11 | { 12 | cout << "new object" << endl; 13 | } 14 | ~A() 15 | { 16 | cout << "delete object" << endl; 17 | } 18 | }; 19 | 20 | A&& func() 21 | { 22 | return move(A()); 23 | } 24 | 25 | int main() 26 | { 27 | A&& a = func(); 28 | cout << "function end" << endl; 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /plugins/pdbdump.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // pdbdump.c - dump symbols from .pdb and executable files (public domain). 3 | // - to compile; cl.exe /Ox /Zi pdbdump.c 4 | // - 5 | // - Martin Ridgers, pdbdump 'at' fireproofgravy.co.uk 6 | //------------------------------------------------------------------------------ 7 | // Taken from https://gist.github.com/BOT-Man-JL/9206a62b067f4c3a84da57bd3ba04a97 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma comment(lib, "dbghelp.lib") 14 | 15 | //------------------------------------------------------------------------------ 16 | const char* g_usage = 17 | "pdbdump.exe - dump symbols from .pdb and executable files." "\n" 18 | " Martin Ridgers, pdbdump 'at' fireproofgravy.co.uk" "\n" 19 | "\n" 20 | " Usage: pdbdump.exe [-csv] [-sasnf] [-r] pdb_or_exe[:BASE]" "\n" 21 | " -t: Enumerate types." "\n" 22 | " -csv: Output comma-separated-values format." "\n" 23 | " -s[asnf]: Sort by (a)ddress, (s)ize, (n)ame, or (f)ile. ASNF to reverse." "\n" 24 | " -r: Resolve names and addresses read from stdin." "\n" 25 | " -w[...]: Wildcard to use when enumerating symbols." "\n" 26 | "\n" 27 | " By default modules (.pdb or .exe files) are loaded with a base address of" "\n" 28 | " 0x400000. This can be overriden by adding a :BASE suffix to the module's" "\n" 29 | " file name. For example; my_project.pdb:0x20030000." "\n" 30 | "\n" 31 | " Examples: 1. Output all symbols from a.pdb and b.dll;" "\n" 32 | " > pdbdump.exe a.pdb b.dll" "\n" 33 | " 2. Output all of a.pdb's function symbols in CSV format;" "\n" 34 | " > pdbdump.exe -csv a.pdb | findstr SymTagFunction" "\n" 35 | " 3. List all symbols starting with 'is_enab';" "\n" 36 | " > pdbdump.exe -wis_enab* a.pdb" "\n" 37 | " 4. Resolve two symbols by name and by address;" "\n" 38 | " > echo 0x401000 is_enabled | pdbdump.exe -r a.pdb" "\n" 39 | ; 40 | 41 | //------------------------------------------------------------------------------ 42 | #define ENABLE_DEBUG_OUTPUT 0 43 | #define ASSERT(x, m, ...) if (!(x)) { fprintf(stderr, m, __VA_ARGS__); \ 44 | exit(-1); } 45 | #define ONE_MB (1024 * 1024) 46 | 47 | //------------------------------------------------------------------------------ 48 | enum e_mode 49 | { 50 | e_mode_resolve_stdin, 51 | e_mode_enum_symbols, 52 | }; 53 | 54 | //------------------------------------------------------------------------------ 55 | enum e_enum_type 56 | { 57 | e_enum_type_symbols, 58 | e_enum_type_types 59 | }; 60 | 61 | //------------------------------------------------------------------------------ 62 | struct _sym_info 63 | { 64 | DWORD64 addr; 65 | int size; 66 | char* name; 67 | char* file; 68 | int tag : 8; 69 | int line : 24; 70 | }; 71 | typedef struct _sym_info sym_info_t; 72 | 73 | //------------------------------------------------------------------------------ 74 | struct _pool 75 | { 76 | char* base; 77 | int committed; 78 | int size; 79 | int used; 80 | }; 81 | typedef struct _pool pool_t; 82 | 83 | //------------------------------------------------------------------------------ 84 | typedef int (sort_func_t)(const sym_info_t*, const sym_info_t*); 85 | 86 | int g_page_size = 0; 87 | HANDLE g_handle = (HANDLE)0x493; 88 | int g_csv_output = 0; 89 | int g_sym_count = 0; 90 | enum e_mode g_mode = e_mode_enum_symbols; 91 | int g_sort_order = 1; 92 | sort_func_t* g_sort_func = NULL; 93 | enum e_enum_type g_enum_type = e_enum_type_symbols; 94 | const char* g_wildcard = "*"; 95 | pool_t g_symbol_pool; 96 | pool_t g_string_pool; 97 | extern const char* g_sym_tag_names[]; /* ...at end of file */ 98 | 99 | //------------------------------------------------------------------------------ 100 | void pool_create(pool_t* pool, int size) 101 | { 102 | pool->base = (char*)VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_READWRITE); 103 | pool->size = size; 104 | pool->committed = 0; 105 | pool->used = 0; 106 | } 107 | 108 | //------------------------------------------------------------------------------ 109 | void pool_destroy(pool_t* pool) 110 | { 111 | VirtualFree(pool->base, 0, MEM_RELEASE); 112 | } 113 | 114 | //------------------------------------------------------------------------------ 115 | void pool_clear(pool_t* pool) 116 | { 117 | pool->used = 0; 118 | } 119 | 120 | //------------------------------------------------------------------------------ 121 | void* pool_alloc(pool_t* pool, int size) 122 | { 123 | int i; 124 | char* addr; 125 | 126 | ASSERT(size < g_page_size, "Allocation to large!"); 127 | 128 | i = pool->used + size; 129 | if (i >= pool->committed) 130 | { 131 | ASSERT(i < pool->size, "Memory pool exhausted."); 132 | VirtualAlloc((void*)(pool->base + pool->committed), g_page_size, 133 | MEM_COMMIT, PAGE_READWRITE 134 | ); 135 | pool->committed += g_page_size; 136 | } 137 | 138 | addr = pool->base + pool->used; 139 | pool->used += size; 140 | return addr; 141 | } 142 | 143 | //------------------------------------------------------------------------------ 144 | int sort_addr(const sym_info_t* lhs, const sym_info_t* rhs) 145 | { 146 | return (int)(lhs->addr - rhs->addr) * g_sort_order; 147 | } 148 | 149 | //------------------------------------------------------------------------------ 150 | int sort_size(const sym_info_t* lhs, const sym_info_t* rhs) 151 | { 152 | return (lhs->size - rhs->size) * g_sort_order; 153 | } 154 | 155 | //------------------------------------------------------------------------------ 156 | int sort_name(const sym_info_t* lhs, const sym_info_t* rhs) 157 | { 158 | return _stricmp(lhs->name, rhs->name) * g_sort_order; 159 | } 160 | 161 | //------------------------------------------------------------------------------ 162 | int sort_file(const sym_info_t* lhs, const sym_info_t* rhs) 163 | { 164 | return _stricmp(lhs->file, rhs->file) * g_sort_order; 165 | } 166 | 167 | //------------------------------------------------------------------------------ 168 | void print_info(const char* info, ...) 169 | { 170 | va_list va; 171 | 172 | va_start(va, info); 173 | vfprintf(stderr, info, va); 174 | va_end(va); 175 | } 176 | 177 | //------------------------------------------------------------------------------ 178 | void dbghelp_to_sym_info(SYMBOL_INFO* info, sym_info_t* sym_info) 179 | { 180 | BOOL ok; 181 | DWORD disp; 182 | IMAGEHLP_LINE64 line; 183 | 184 | // General properties 185 | sym_info->addr = info->Address; 186 | sym_info->size = info->Size; 187 | sym_info->tag = info->Tag; 188 | 189 | // Symbol name 190 | sym_info->name = pool_alloc(&g_string_pool, info->NameLen + 1); 191 | strncpy(sym_info->name, info->Name, info->NameLen + 1); 192 | sym_info->name[info->NameLen] = NULL; 193 | 194 | // Get file and line number info. 195 | line.SizeOfStruct = sizeof(line); 196 | ok = SymGetLineFromAddr64(g_handle, info->Address, &disp, &line); 197 | if ((ok != FALSE) && line.FileName) 198 | { 199 | sym_info->line = line.LineNumber; 200 | sym_info->file = pool_alloc(&g_string_pool, strlen(line.FileName) + 1); 201 | strcpy(sym_info->file, line.FileName); 202 | } 203 | else 204 | { 205 | sym_info->line = 0; 206 | sym_info->file = "?"; 207 | } 208 | } 209 | 210 | //------------------------------------------------------------------------------ 211 | BOOL CALLBACK enum_proc(SYMBOL_INFO* info, ULONG size, void* param) 212 | { 213 | sym_info_t* sym_info; 214 | 215 | sym_info = (sym_info_t*)pool_alloc(&g_symbol_pool, sizeof(sym_info_t)); 216 | dbghelp_to_sym_info(info, sym_info); 217 | 218 | if (!(g_sym_count % 100)) 219 | { 220 | print_info("\r%d", g_sym_count); 221 | } 222 | ++g_sym_count; 223 | 224 | return TRUE; 225 | } 226 | 227 | //------------------------------------------------------------------------------ 228 | void print_symbol(const sym_info_t* sym_info) 229 | { 230 | const char* format; 231 | 232 | format = "%016llx %10d %-21s %-32s %s(%d)\n"; 233 | if (g_csv_output) 234 | { 235 | format = "\"%llx\",%d,\"%s\",\"%s\",\"%s\",%d\n"; 236 | } 237 | 238 | printf( 239 | format, sym_info->addr, sym_info->size, g_sym_tag_names[sym_info->tag], 240 | sym_info->name, sym_info->file, sym_info->line 241 | ); 242 | } 243 | 244 | //------------------------------------------------------------------------------ 245 | int create_pools(uintptr_t base_addr) 246 | { 247 | BOOL ok; 248 | FILE* in; 249 | int size, i; 250 | const char* guide; 251 | 252 | // Fetch PDB file for the module. 253 | IMAGEHLP_MODULE64 module = { sizeof(module) }; 254 | ok = SymGetModuleInfo64(g_handle, base_addr, &module); 255 | ASSERT(ok != FALSE, "Unexpected failure from SymGetSymbolFile()."); 256 | 257 | guide = module.LoadedPdbName; 258 | 259 | // An .exe with no symbols available? 260 | if (!guide || guide[0] == '\0') 261 | { 262 | return 0; 263 | } 264 | 265 | // Get file size. 266 | in = fopen(guide, "rb"); 267 | ASSERT(in != NULL, "Failed to open pool-size guide file."); 268 | 269 | fseek(in, 0, SEEK_END); 270 | size = ftell(in); 271 | fclose(in); 272 | 273 | // Use anecdotal evidence to guess at suitable pool sizes :). 274 | i = size / 4; 275 | pool_create(&g_string_pool, (i < ONE_MB) ? ONE_MB : i); 276 | 277 | i = size / 25; 278 | pool_create(&g_symbol_pool, (i < ONE_MB) ? ONE_MB : i); 279 | 280 | return 1; 281 | } 282 | 283 | //------------------------------------------------------------------------------ 284 | uintptr_t load_module(const char* pdb_file) 285 | { 286 | char buffer[512]; 287 | char* colon; 288 | uintptr_t base_addr = 0x400000; 289 | 290 | strncpy(buffer, pdb_file, 512); 291 | buffer[sizeof(buffer) - 1] = '\0'; 292 | 293 | // Is there a base address tag on the end of the file name? 294 | colon = strrchr(buffer, ':'); 295 | if (colon && (ptrdiff_t)(colon - buffer) > 1) 296 | { 297 | *colon++ = '\0'; 298 | base_addr = (uintptr_t)_strtoui64(colon, NULL, 0); 299 | } 300 | 301 | base_addr = (size_t)SymLoadModuleEx(g_handle, NULL, buffer, NULL, 302 | base_addr, 0x7fffffff, NULL, 0 303 | ); 304 | 305 | return base_addr; 306 | } 307 | 308 | //------------------------------------------------------------------------------ 309 | void output_symbols(const char* pdb_file) 310 | { 311 | int i; 312 | uintptr_t base_addr; 313 | DWORD ok; 314 | 315 | // Load module. 316 | base_addr = load_module(pdb_file); 317 | if (!base_addr) 318 | { 319 | print_info("Failed to load symbols for '%s' (Error %d)", pdb_file, 320 | GetLastError() 321 | ); 322 | return; 323 | } 324 | 325 | if (!create_pools(base_addr)) 326 | { 327 | print_info("No symbols found for '%s'", pdb_file); 328 | return; 329 | } 330 | 331 | g_sym_count = 0; 332 | 333 | // Do the enumeration. 334 | print_info("Enumerating...\n"); 335 | switch (g_enum_type) 336 | { 337 | case e_enum_type_symbols: 338 | SymEnumSymbols(g_handle, base_addr, g_wildcard, enum_proc, NULL); 339 | break; 340 | 341 | case e_enum_type_types: 342 | SymEnumTypes(g_handle, base_addr, enum_proc, NULL); 343 | break; 344 | } 345 | print_info("\r%d\n...Done!\n", g_sym_count); 346 | 347 | // Done. 348 | ok = SymUnloadModule64(g_handle, (DWORD64)base_addr); 349 | ASSERT(ok != FALSE, "Failed unloading module."); 350 | 351 | // Sort. 352 | if (g_sort_func != NULL) 353 | { 354 | qsort(g_symbol_pool.base, g_sym_count, sizeof(sym_info_t), 355 | (int (*)(const void*, const void*))g_sort_func 356 | ); 357 | } 358 | 359 | // Print to stdout 360 | for (i = 0; i < g_sym_count; ++i) 361 | { 362 | sym_info_t* sym_info = ((sym_info_t*)g_symbol_pool.base) + i; 363 | print_symbol(sym_info); 364 | } 365 | 366 | pool_destroy(&g_string_pool); 367 | pool_destroy(&g_symbol_pool); 368 | } 369 | 370 | //------------------------------------------------------------------------------ 371 | void resolve_stdin() 372 | { 373 | pool_create(&g_string_pool, g_page_size); 374 | 375 | while (!feof(stdin)) 376 | { 377 | int i; 378 | int state; 379 | char buffer[256]; 380 | BOOL ok; 381 | 382 | struct { 383 | SYMBOL_INFO info; 384 | char name_buf[256]; 385 | } si; 386 | 387 | si.info.SizeOfStruct = sizeof(si.info); 388 | si.info.MaxNameLen = sizeof(si.name_buf); 389 | 390 | // Parse things on the command line. 391 | state = 0; 392 | i = 0; 393 | while (!feof(stdin) && (i < sizeof(buffer) - 1)) 394 | { 395 | fread(buffer + i, 1, 1, stdin); 396 | if (!!isspace(buffer[i]) == state) 397 | { 398 | if (++state > 1) 399 | { 400 | break; 401 | } 402 | } 403 | 404 | i += state; 405 | } 406 | 407 | buffer[i] = '\0'; 408 | if (i == 0) 409 | { 410 | continue; 411 | } 412 | 413 | if (isdigit(buffer[0])) 414 | { 415 | DWORD64 addr = (DWORD64)_strtoui64(buffer, NULL, 0); 416 | ok = SymFromAddr(g_handle, addr, NULL, &si.info); 417 | } 418 | else 419 | { 420 | ok = SymFromName(g_handle, buffer, &si.info); 421 | } 422 | 423 | pool_clear(&g_string_pool); 424 | if (ok != FALSE) 425 | { 426 | sym_info_t sym_info; 427 | dbghelp_to_sym_info(&si.info, &sym_info); 428 | print_symbol(&sym_info); 429 | } 430 | } 431 | 432 | pool_destroy(&g_string_pool); 433 | } 434 | 435 | //------------------------------------------------------------------------------ 436 | void parse_args(int argc, char** argv) 437 | { 438 | int i; 439 | 440 | for (i = 0; i < argc; ++i) 441 | { 442 | const char* arg = argv[i]; 443 | if (strcmp(arg, "-csv") == 0) 444 | { 445 | g_csv_output = 1; 446 | } 447 | else if (strncmp(arg, "-s", 2) == 0) 448 | { 449 | char c = arg[2]; 450 | c = isupper(c) ? tolower(c) : c; 451 | switch (c) 452 | { 453 | case '\0': 454 | case 'a': g_sort_func = sort_addr; break; 455 | case 's': g_sort_func = sort_size; break; 456 | case 'n': g_sort_func = sort_name; break; 457 | case 'f': g_sort_func = sort_file; break; 458 | } 459 | 460 | g_sort_order = (arg[2] < 'a') ? -1 : 1; 461 | } 462 | else if (strcmp(arg, "-r") == 0) 463 | { 464 | g_mode = e_mode_resolve_stdin; 465 | } 466 | else if (strcmp(arg, "-t") == 0) 467 | { 468 | g_enum_type = e_enum_type_types; 469 | } 470 | else if (strncmp(arg, "-w", 2) == 0) 471 | { 472 | if (arg[2] != '\0') 473 | { 474 | g_wildcard = arg + 2; 475 | } 476 | } 477 | } 478 | } 479 | 480 | //------------------------------------------------------------------------------ 481 | int main(int argc, char** argv) 482 | { 483 | int i; 484 | BOOL ok; 485 | DWORD options; 486 | SYSTEM_INFO sys_info; 487 | 488 | if (argc <= 1) 489 | { 490 | puts(g_usage); 491 | return -1; 492 | } 493 | 494 | --argc; 495 | ++argv; 496 | parse_args(argc, argv); 497 | 498 | // Get page size. 499 | GetSystemInfo(&sys_info); 500 | g_page_size = sys_info.dwPageSize; 501 | 502 | // Initialise DbgHelp 503 | options = SymGetOptions(); 504 | options &= ~SYMOPT_DEFERRED_LOADS; 505 | options |= SYMOPT_LOAD_LINES; 506 | options |= SYMOPT_IGNORE_NT_SYMPATH; 507 | #if ENABLE_DEBUG_OUTPUT 508 | options |= SYMOPT_DEBUG; 509 | #endif 510 | options |= SYMOPT_UNDNAME; 511 | SymSetOptions(options); 512 | 513 | ok = SymInitialize(g_handle, NULL, FALSE); 514 | ASSERT(ok != FALSE, "Failed to initialise symbol handler."); 515 | 516 | // Output each .PDB file specified on the command line. 517 | switch (g_mode) 518 | { 519 | case e_mode_enum_symbols: 520 | for (i = 0; i < argc; ++i) 521 | { 522 | const char* arg = argv[i]; 523 | if (arg[0] != '-') 524 | { 525 | output_symbols(arg); 526 | } 527 | } 528 | break; 529 | 530 | case e_mode_resolve_stdin: 531 | for (i = 0; i < argc; ++i) 532 | { 533 | const char* arg = argv[i]; 534 | if (arg[0] != '-') 535 | { 536 | load_module(arg); 537 | } 538 | } 539 | resolve_stdin(); 540 | break; 541 | } 542 | 543 | SymCleanup(g_handle); 544 | return 0; 545 | } 546 | 547 | //------------------------------------------------------------------------------ 548 | const char* g_sym_tag_names[] = { 549 | "SymTagNull", "SymTagExe", "SymTagCompiland", "SymTagCompilandDetails", 550 | "SymTagCompilandEnv", "SymTagFunction", "SymTagBlock", "SymTagData", 551 | "SymTagAnnotation", "SymTagLabel", "SymTagPublicSymbol", "SymTagUDT", 552 | "SymTagEnum", "SymTagFunctionType", "SymTagPointerType", "SymTagArrayType", 553 | "SymTagBaseType", "SymTagTypedef", "SymTagBaseClass", "SymTagFriend", 554 | "SymTagFunctionArgType", "SymTagFuncDebugStart", "SymTagFuncDebugEnd", 555 | "SymTagUsingNamespace", "SymTagVTableShape", "SymTagVTable", "SymTagCustom", 556 | "SymTagThunk", "SymTagCustomType", "SymTagManagedType", "SymTagDimension" 557 | }; -------------------------------------------------------------------------------- /plugins/postfix.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # globally 8 | set(CMAKE_DEBUG_POSTFIX "_d") 9 | 10 | # per-target 11 | # set_target_properties(hello PROPERTIES DEBUG_POSTFIX "_d") 12 | -------------------------------------------------------------------------------- /plugins/properties.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # 8 | # Usage: 9 | # print_target_properties(opencv_core) 10 | # print_directory_properties(.) 11 | # print_global_properties() 12 | # 13 | 14 | function(print_target_properties TARGET) 15 | message("target properties for ${TARGET}") 16 | 17 | set(prop_lst 18 | ADDITIONAL_CLEAN_FILES 19 | AIX_EXPORT_ALL_SYMBOLS 20 | ALIAS_GLOBAL 21 | ALIASED_TARGET 22 | ANDROID_ANT_ADDITIONAL_OPTIONS 23 | ANDROID_API 24 | ANDROID_API_MIN 25 | ANDROID_ARCH 26 | ANDROID_ASSETS_DIRECTORIES 27 | ANDROID_GUI 28 | ANDROID_JAR_DEPENDENCIES 29 | ANDROID_JAR_DIRECTORIES 30 | ANDROID_JAVA_SOURCE_DIR 31 | ANDROID_NATIVE_LIB_DEPENDENCIES 32 | ANDROID_NATIVE_LIB_DIRECTORIES 33 | ANDROID_PROCESS_MAX 34 | ANDROID_PROGUARD 35 | ANDROID_PROGUARD_CONFIG_PATH 36 | ANDROID_SECURE_PROPS_PATH 37 | ANDROID_SKIP_ANT_STEP 38 | ANDROID_STL_TYPE 39 | ARCHIVE_OUTPUT_DIRECTORY 40 | #ARCHIVE_OUTPUT_DIRECTORY_ 41 | ARCHIVE_OUTPUT_NAME 42 | #ARCHIVE_OUTPUT_NAME_ 43 | AUTOGEN_BETTER_GRAPH_MULTI_CONFIG 44 | AUTOGEN_BUILD_DIR 45 | AUTOGEN_COMMAND_LINE_LENGTH_MAX 46 | AUTOGEN_ORIGIN_DEPENDS 47 | AUTOGEN_PARALLEL 48 | AUTOGEN_TARGET_DEPENDS 49 | AUTOGEN_USE_SYSTEM_INCLUDE 50 | AUTOMOC 51 | AUTOMOC_COMPILER_PREDEFINES 52 | AUTOMOC_DEPEND_FILTERS 53 | AUTOMOC_EXECUTABLE 54 | AUTOMOC_MACRO_NAMES 55 | AUTOMOC_MOC_OPTIONS 56 | AUTOMOC_PATH_PREFIX 57 | AUTORCC 58 | AUTORCC_EXECUTABLE 59 | AUTORCC_OPTIONS 60 | AUTOUIC 61 | AUTOUIC_EXECUTABLE 62 | AUTOUIC_OPTIONS 63 | AUTOUIC_SEARCH_PATHS 64 | BINARY_DIR 65 | BUILD_RPATH 66 | BUILD_RPATH_USE_ORIGIN 67 | BUILD_WITH_INSTALL_NAME_DIR 68 | BUILD_WITH_INSTALL_RPATH 69 | BUNDLE 70 | BUNDLE_EXTENSION 71 | C_EXTENSIONS 72 | C_STANDARD 73 | C_STANDARD_REQUIRED 74 | COMMON_LANGUAGE_RUNTIME 75 | COMPATIBLE_INTERFACE_BOOL 76 | COMPATIBLE_INTERFACE_NUMBER_MAX 77 | COMPATIBLE_INTERFACE_NUMBER_MIN 78 | COMPATIBLE_INTERFACE_STRING 79 | COMPILE_DEFINITIONS 80 | COMPILE_FEATURES 81 | COMPILE_FLAGS 82 | COMPILE_OPTIONS 83 | COMPILE_PDB_NAME 84 | #COMPILE_PDB_NAME_ 85 | COMPILE_PDB_OUTPUT_DIRECTORY 86 | #COMPILE_PDB_OUTPUT_DIRECTORY_ 87 | COMPILE_WARNING_AS_ERROR 88 | #_OUTPUT_NAME 89 | #_POSTFIX 90 | 91 | CROSSCOMPILING_EMULATOR 92 | CUDA_ARCHITECTURES 93 | CUDA_CUBIN_COMPILATION 94 | CUDA_EXTENSIONS 95 | CUDA_FATBIN_COMPILATION 96 | CUDA_OPTIX_COMPILATION 97 | CUDA_PTX_COMPILATION 98 | CUDA_RESOLVE_DEVICE_SYMBOLS 99 | CUDA_RUNTIME_LIBRARY 100 | CUDA_SEPARABLE_COMPILATION 101 | CUDA_STANDARD 102 | CUDA_STANDARD_REQUIRED 103 | CXX_EXTENSIONS 104 | CXX_MODULE_DIRS 105 | #CXX_MODULE_DIRS_ 106 | CXX_MODULE_SET 107 | #CXX_MODULE_SET_ 108 | CXX_MODULE_SETS 109 | CXX_SCAN_FOR_MODULES 110 | CXX_STANDARD 111 | CXX_STANDARD_REQUIRED 112 | DEBUG_POSTFIX 113 | DEFINE_SYMBOL 114 | DEPLOYMENT_ADDITIONAL_FILES 115 | DEPLOYMENT_REMOTE_DIRECTORY 116 | DEPRECATION 117 | DISABLE_PRECOMPILE_HEADERS 118 | DLL_NAME_WITH_SOVERSION 119 | DOTNET_SDK 120 | DOTNET_TARGET_FRAMEWORK 121 | DOTNET_TARGET_FRAMEWORK_VERSION 122 | EchoString 123 | ENABLE_EXPORTS 124 | EXCLUDE_FROM_ALL 125 | EXCLUDE_FROM_DEFAULT_BUILD 126 | #EXCLUDE_FROM_DEFAULT_BUILD_ 127 | EXPORT_COMPILE_COMMANDS 128 | EXPORT_FIND_PACKAGE_NAME 129 | EXPORT_NAME 130 | EXPORT_NO_SYSTEM 131 | EXPORT_PROPERTIES 132 | FOLDER 133 | Fortran_BUILDING_INSTRINSIC_MODULES 134 | Fortran_FORMAT 135 | Fortran_MODULE_DIRECTORY 136 | Fortran_PREPROCESS 137 | FRAMEWORK 138 | #FRAMEWORK_MULTI_CONFIG_POSTFIX_ 139 | FRAMEWORK_VERSION 140 | GENERATOR_FILE_NAME 141 | GHS_INTEGRITY_APP 142 | GHS_NO_SOURCE_GROUP_FILE 143 | GNUtoMS 144 | HAS_CXX 145 | HEADER_DIRS 146 | #HEADER_DIRS_ 147 | HEADER_SET 148 | #HEADER_SET_ 149 | HEADER_SETS 150 | HIP_ARCHITECTURES 151 | HIP_EXTENSIONS 152 | HIP_STANDARD 153 | HIP_STANDARD_REQUIRED 154 | IMPLICIT_DEPENDS_INCLUDE_TRANSFORM 155 | IMPORTED 156 | IMPORTED_COMMON_LANGUAGE_RUNTIME 157 | IMPORTED_CONFIGURATIONS 158 | IMPORTED_CXX_MODULES_COMPILE_DEFINITIONS 159 | IMPORTED_CXX_MODULES_COMPILE_FEATURES 160 | IMPORTED_CXX_MODULES_COMPILE_OPTIONS 161 | IMPORTED_CXX_MODULES_INCLUDE_DIRECTORIES 162 | IMPORTED_CXX_MODULES_LINK_LIBRARIES 163 | IMPORTED_GLOBAL 164 | IMPORTED_IMPLIB 165 | #IMPORTED_IMPLIB_ 166 | IMPORTED_LIBNAME 167 | #IMPORTED_LIBNAME_ 168 | IMPORTED_LINK_DEPENDENT_LIBRARIES 169 | #IMPORTED_LINK_DEPENDENT_LIBRARIES_ 170 | IMPORTED_LINK_INTERFACE_LANGUAGES 171 | #IMPORTED_LINK_INTERFACE_LANGUAGES_ 172 | IMPORTED_LINK_INTERFACE_LIBRARIES 173 | #IMPORTED_LINK_INTERFACE_LIBRARIES_ 174 | IMPORTED_LINK_INTERFACE_MULTIPLICITY 175 | #IMPORTED_LINK_INTERFACE_MULTIPLICITY_ 176 | IMPORTED_LOCATION 177 | #IMPORTED_LOCATION_ 178 | IMPORTED_NO_SONAME 179 | #IMPORTED_NO_SONAME_ 180 | IMPORTED_OBJECTS 181 | #IMPORTED_OBJECTS_ 182 | IMPORTED_SONAME 183 | #IMPORTED_SONAME_ 184 | IMPORT_PREFIX 185 | IMPORT_SUFFIX 186 | INCLUDE_DIRECTORIES 187 | INSTALL_NAME_DIR 188 | INSTALL_REMOVE_ENVIRONMENT_RPATH 189 | INSTALL_RPATH 190 | INSTALL_RPATH_USE_LINK_PATH 191 | INTERFACE_AUTOMOC_MACRO_NAMES 192 | INTERFACE_AUTOUIC_OPTIONS 193 | INTERFACE_COMPILE_DEFINITIONS 194 | INTERFACE_COMPILE_FEATURES 195 | INTERFACE_COMPILE_OPTIONS 196 | INTERFACE_CXX_MODULE_SETS 197 | INTERFACE_HEADER_SETS 198 | INTERFACE_HEADER_SETS_TO_VERIFY 199 | INTERFACE_INCLUDE_DIRECTORIES 200 | INTERFACE_LINK_DEPENDS 201 | INTERFACE_LINK_DIRECTORIES 202 | INTERFACE_LINK_LIBRARIES 203 | INTERFACE_LINK_LIBRARIES_DIRECT 204 | INTERFACE_LINK_LIBRARIES_DIRECT_EXCLUDE 205 | INTERFACE_LINK_OPTIONS 206 | INTERFACE_POSITION_INDEPENDENT_CODE 207 | INTERFACE_PRECOMPILE_HEADERS 208 | INTERFACE_SOURCES 209 | INTERFACE_SYSTEM_INCLUDE_DIRECTORIES 210 | INTERPROCEDURAL_OPTIMIZATION 211 | #INTERPROCEDURAL_OPTIMIZATION_ 212 | ISPC_HEADER_DIRECTORY 213 | ISPC_HEADER_SUFFIX 214 | ISPC_INSTRUCTION_SETS 215 | JOB_POOL_COMPILE 216 | JOB_POOL_LINK 217 | JOB_POOL_PRECOMPILE_HEADER 218 | LABELS 219 | 220 | C_CLANG_TIDY 221 | C_CLANG_TIDY_EXPORT_FIXES_DIR 222 | C_COMPILER_LAUNCHER 223 | C_CPPCHECK 224 | C_CPPLINT 225 | C_EXTENSIONS 226 | C_INCLUDE_WHAT_YOU_USE 227 | C_LINKER_LAUNCHER 228 | C_STANDARD 229 | C_STANDARD_REQUIRED 230 | C_VISIBILITY_PRESET 231 | 232 | CXX_CLANG_TIDY 233 | CXX_CLANG_TIDY_EXPORT_FIXES_DIR 234 | CXX_COMPILER_LAUNCHER 235 | CXX_CPPCHECK 236 | CXX_CPPLINT 237 | CXX_EXTENSIONS 238 | CXX_INCLUDE_WHAT_YOU_USE 239 | CXX_LINKER_LAUNCHER 240 | CXX_STANDARD 241 | CXX_STANDARD_REQUIRED 242 | CXX_VISIBILITY_PRESET 243 | 244 | LIBRARY_OUTPUT_DIRECTORY 245 | #LIBRARY_OUTPUT_DIRECTORY_ 246 | LIBRARY_OUTPUT_NAME 247 | #LIBRARY_OUTPUT_NAME_ 248 | LINK_DEPENDS 249 | LINK_DEPENDS_NO_SHARED 250 | LINK_DIRECTORIES 251 | LINK_FLAGS 252 | #LINK_FLAGS_ 253 | LINK_INTERFACE_LIBRARIES 254 | #LINK_INTERFACE_LIBRARIES_ 255 | LINK_INTERFACE_MULTIPLICITY 256 | #LINK_INTERFACE_MULTIPLICITY_ 257 | LINK_LIBRARIES 258 | LINK_LIBRARIES_ONLY_TARGETS 259 | LINK_LIBRARY_OVERRIDE 260 | #LINK_LIBRARY_OVERRIDE_ 261 | LINK_OPTIONS 262 | LINK_SEARCH_END_STATIC 263 | LINK_SEARCH_START_STATIC 264 | LINK_WHAT_YOU_USE 265 | LINKER_LANGUAGE 266 | LINKER_TYPE 267 | LOCATION 268 | #LOCATION_ 269 | MACHO_COMPATIBILITY_VERSION 270 | MACHO_CURRENT_VERSION 271 | MACOSX_BUNDLE 272 | MACOSX_BUNDLE_INFO_PLIST 273 | MACOSX_FRAMEWORK_INFO_PLIST 274 | MACOSX_RPATH 275 | MANUALLY_ADDED_DEPENDENCIES 276 | #MAP_IMPORTED_CONFIG_ 277 | MSVC_DEBUG_INFORMATION_FORMAT 278 | MSVC_RUNTIME_LIBRARY 279 | NAME 280 | NO_SONAME 281 | NO_SYSTEM_FROM_IMPORTED 282 | OBJC_EXTENSIONS 283 | OBJC_STANDARD 284 | OBJC_STANDARD_REQUIRED 285 | OBJCXX_EXTENSIONS 286 | OBJCXX_STANDARD 287 | OBJCXX_STANDARD_REQUIRED 288 | OPTIMIZE_DEPENDENCIES 289 | OSX_ARCHITECTURES 290 | #OSX_ARCHITECTURES_ 291 | OUTPUT_NAME 292 | #OUTPUT_NAME_ 293 | PCH_INSTANTIATE_TEMPLATES 294 | PCH_WARN_INVALID 295 | PDB_NAME 296 | #PDB_NAME_ 297 | PDB_OUTPUT_DIRECTORY 298 | #PDB_OUTPUT_DIRECTORY_ 299 | POSITION_INDEPENDENT_CODE 300 | PRECOMPILE_HEADERS 301 | PRECOMPILE_HEADERS_REUSE_FROM 302 | PREFIX 303 | PRIVATE_HEADER 304 | PROJECT_LABEL 305 | PUBLIC_HEADER 306 | RESOURCE 307 | RULE_LAUNCH_COMPILE 308 | RULE_LAUNCH_CUSTOM 309 | RULE_LAUNCH_LINK 310 | RUNTIME_OUTPUT_DIRECTORY 311 | #RUNTIME_OUTPUT_DIRECTORY_ 312 | RUNTIME_OUTPUT_NAME 313 | #RUNTIME_OUTPUT_NAME_ 314 | SKIP_BUILD_RPATH 315 | SOURCE_DIR 316 | SOURCES 317 | SOVERSION 318 | STATIC_LIBRARY_FLAGS 319 | #STATIC_LIBRARY_FLAGS_ 320 | STATIC_LIBRARY_OPTIONS 321 | SUFFIX 322 | Swift_COMPILATION_MODE 323 | Swift_DEPENDENCIES_FILE 324 | Swift_LANGUAGE_VERSION 325 | Swift_MODULE_DIRECTORY 326 | Swift_MODULE_NAME 327 | SYSTEM 328 | TEST_LAUNCHER 329 | TYPE 330 | UNITY_BUILD 331 | UNITY_BUILD_BATCH_SIZE 332 | UNITY_BUILD_CODE_AFTER_INCLUDE 333 | UNITY_BUILD_CODE_BEFORE_INCLUDE 334 | UNITY_BUILD_MODE 335 | UNITY_BUILD_UNIQUE_ID 336 | VERIFY_INTERFACE_HEADER_SETS 337 | VERSION 338 | VISIBILITY_INLINES_HIDDEN 339 | VS_CONFIGURATION_TYPE 340 | VS_DEBUGGER_COMMAND 341 | VS_DEBUGGER_COMMAND_ARGUMENTS 342 | VS_DEBUGGER_ENVIRONMENT 343 | VS_DEBUGGER_WORKING_DIRECTORY 344 | VS_DESKTOP_EXTENSIONS_VERSION 345 | VS_DOTNET_DOCUMENTATION_FILE 346 | #VS_DOTNET_REFERENCE_ 347 | #VS_DOTNET_REFERENCEPROP__TAG_ 348 | VS_DOTNET_REFERENCES 349 | VS_DOTNET_REFERENCES_COPY_LOCAL 350 | VS_DOTNET_STARTUP_OBJECT 351 | VS_DOTNET_TARGET_FRAMEWORK_VERSION 352 | VS_DPI_AWARE 353 | VS_GLOBAL_KEYWORD 354 | VS_GLOBAL_PROJECT_TYPES 355 | VS_GLOBAL_ROOTNAMESPACE 356 | VS_GLOBAL_ 357 | VS_IOT_EXTENSIONS_VERSION 358 | VS_IOT_STARTUP_TASK 359 | VS_JUST_MY_CODE_DEBUGGING 360 | VS_KEYWORD 361 | VS_MOBILE_EXTENSIONS_VERSION 362 | VS_NO_COMPILE_BATCHING 363 | VS_NO_SOLUTION_DEPLOY 364 | VS_PACKAGE_REFERENCES 365 | VS_PLATFORM_TOOLSET 366 | VS_PROJECT_IMPORT 367 | VS_SCC_AUXPATH 368 | VS_SCC_LOCALPATH 369 | VS_SCC_PROJECTNAME 370 | VS_SCC_PROVIDER 371 | VS_SDK_REFERENCES 372 | VS_SOLUTION_DEPLOY 373 | #VS_SOURCE_SETTINGS_ 374 | VS_USER_PROPS 375 | VS_WINDOWS_TARGET_PLATFORM_MIN_VERSION 376 | VS_WINRT_COMPONENT 377 | VS_WINRT_REFERENCES 378 | WATCOM_RUNTIME_LIBRARY 379 | WIN32_EXECUTABLE 380 | WINDOWS_EXPORT_ALL_SYMBOLS 381 | #XCODE_ATTRIBUTE_ 382 | XCODE_EMBED_FRAMEWORKS_CODE_SIGN_ON_COPY 383 | XCODE_EMBED_FRAMEWORKS_REMOVE_HEADERS_ON_COPY 384 | # XCODE_EMBED_ 385 | # XCODE_EMBED__CODE_SIGN_ON_COPY 386 | # XCODE_EMBED__PATH 387 | # XCODE_EMBED__REMOVE_HEADERS_ON_COPY 388 | XCODE_EXPLICIT_FILE_TYPE 389 | XCODE_GENERATE_SCHEME 390 | XCODE_LINK_BUILD_PHASE_MODE 391 | XCODE_PRODUCT_TYPE 392 | XCODE_SCHEME_ADDRESS_SANITIZER 393 | XCODE_SCHEME_ADDRESS_SANITIZER_USE_AFTER_RETURN 394 | XCODE_SCHEME_ARGUMENTS 395 | XCODE_SCHEME_DEBUG_AS_ROOT 396 | XCODE_SCHEME_DEBUG_DOCUMENT_VERSIONING 397 | XCODE_SCHEME_DISABLE_MAIN_THREAD_CHECKER 398 | XCODE_SCHEME_DYNAMIC_LIBRARY_LOADS 399 | XCODE_SCHEME_DYNAMIC_LINKER_API_USAGE 400 | XCODE_SCHEME_ENABLE_GPU_API_VALIDATION 401 | XCODE_SCHEME_ENABLE_GPU_FRAME_CAPTURE_MODE 402 | XCODE_SCHEME_ENABLE_GPU_SHADER_VALIDATION 403 | XCODE_SCHEME_ENVIRONMENT 404 | XCODE_SCHEME_EXECUTABLE 405 | XCODE_SCHEME_GUARD_MALLOC 406 | XCODE_SCHEME_LAUNCH_CONFIGURATION 407 | XCODE_SCHEME_LAUNCH_MODE 408 | XCODE_SCHEME_MAIN_THREAD_CHECKER_STOP 409 | XCODE_SCHEME_MALLOC_GUARD_EDGES 410 | XCODE_SCHEME_MALLOC_SCRIBBLE 411 | XCODE_SCHEME_MALLOC_STACK 412 | XCODE_SCHEME_THREAD_SANITIZER 413 | XCODE_SCHEME_THREAD_SANITIZER_STOP 414 | XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER 415 | XCODE_SCHEME_UNDEFINED_BEHAVIOUR_SANITIZER_STOP 416 | XCODE_SCHEME_WORKING_DIRECTORY 417 | XCODE_SCHEME_ZOMBIE_OBJECTS 418 | XCODE_XCCONFIG 419 | XCTEST 420 | ) 421 | 422 | foreach(prop ${prop_lst}) 423 | # get_target_property(${prop} ${TARGET} ${prop}) 424 | # message(" ${prop}: ${${prop}}") 425 | get_target_property(prop_value ${TARGET} ${prop}) 426 | if(prop_value) 427 | message(" ${prop}: ${prop_value}") 428 | endif() 429 | endforeach() 430 | endfunction() 431 | 432 | 433 | function(print_directory_properties DIRECTORY) 434 | message("directory properties for ${DIRECTORY}") 435 | 436 | set(prop_lst 437 | ADDITIONAL_CLEAN_FILES 438 | BINARY_DIR 439 | BUILDSYSTEM_TARGETS 440 | CACHE_VARIABLES 441 | CLEAN_NO_CUSTOM 442 | CMAKE_CONFIGURE_DEPENDS 443 | COMPILE_DEFINITIONS 444 | COMPILE_OPTIONS 445 | DEFINITIONS 446 | EXCLUDE_FROM_ALL 447 | IMPLICIT_DEPENDS_INCLUDE_TRANSFORM 448 | IMPORTED_TARGETS 449 | INCLUDE_DIRECTORIES 450 | INCLUDE_REGULAR_EXPRESSION 451 | LABELS 452 | LINK_DIRECTORIES 453 | LINK_OPTIONS 454 | LISTFILE_STACK 455 | MACROS 456 | PARENT_DIRECTORY 457 | RULE_LAUNCH_COMPILE 458 | RULE_LAUNCH_CUSTOM 459 | RULE_LAUNCH_LINK 460 | SOURCE_DIR 461 | SUBDIRECTORIES 462 | SYSTEM 463 | TESTS 464 | TEST_INCLUDE_FILES 465 | VARIABLES 466 | VS_GLOBAL_SECTION_POST_
467 | VS_GLOBAL_SECTION_PRE_
468 | VS_STARTUP_PROJECT 469 | ) 470 | foreach(prop ${prop_lst}) 471 | get_directory_property(prop_value 472 | DIRECTORY ${DIRECTORY} 473 | ${prop} 474 | ) 475 | if(prop_value) 476 | message(" ${prop}: ${prop_value}") 477 | endif() 478 | endforeach() 479 | endfunction() 480 | 481 | function(print_global_properties) 482 | message("global properties:") 483 | set(prop_lst 484 | ALLOW_DUPLICATE_CUSTOM_TARGETS 485 | AUTOGEN_SOURCE_GROUP 486 | AUTOGEN_TARGETS_FOLDER 487 | AUTOMOC_SOURCE_GROUP 488 | AUTOMOC_TARGETS_FOLDER 489 | AUTORCC_SOURCE_GROUP 490 | AUTOUIC_SOURCE_GROUP 491 | CMAKE_C_KNOWN_FEATURES 492 | CMAKE_CUDA_KNOWN_FEATURES 493 | CMAKE_CXX_KNOWN_FEATURES 494 | CMAKE_ROLE 495 | DEBUG_CONFIGURATIONS 496 | DISABLED_FEATURES 497 | ECLIPSE_EXTRA_CPROJECT_CONTENTS 498 | ECLIPSE_EXTRA_NATURES 499 | ENABLED_FEATURES 500 | ENABLED_LANGUAGES 501 | FIND_LIBRARY_USE_LIB32_PATHS 502 | FIND_LIBRARY_USE_LIB64_PATHS 503 | FIND_LIBRARY_USE_LIBX32_PATHS 504 | FIND_LIBRARY_USE_OPENBSD_VERSIONING 505 | GENERATOR_IS_MULTI_CONFIG 506 | GLOBAL_DEPENDS_DEBUG_MODE 507 | GLOBAL_DEPENDS_NO_CYCLES 508 | IN_TRY_COMPILE 509 | JOB_POOLS 510 | PACKAGES_FOUND 511 | PACKAGES_NOT_FOUND 512 | PREDEFINED_TARGETS_FOLDER 513 | REPORT_UNDEFINED_PROPERTIES 514 | RULE_LAUNCH_COMPILE 515 | RULE_LAUNCH_CUSTOM 516 | RULE_LAUNCH_LINK 517 | RULE_MESSAGES 518 | TARGET_ARCHIVES_MAY_BE_SHARED_LIBS 519 | TARGET_MESSAGES 520 | TARGET_SUPPORTS_SHARED_LIBS 521 | USE_FOLDERS 522 | XCODE_EMIT_EFFECTIVE_PLATFORM_NAME 523 | ) 524 | 525 | foreach(prop ${prop_lst}) 526 | get_property(prop_value 527 | GLOBAL 528 | PROPERTY DEBUG_CONFIGURATIONS 529 | ) 530 | if(prop_value) 531 | message(" ${prop}: ${prop_value}") 532 | endif() 533 | endforeach() 534 | endfunction() -------------------------------------------------------------------------------- /plugins/source_group.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-11-14 23:10:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | # Show folder structure in Visual Studio / Xcode 8 | function(assign_source_group) 9 | foreach(_source IN ITEMS ${ARGN}) 10 | if (IS_ABSOLUTE "${_source}") 11 | file(RELATIVE_PATH _source_rel "${CMAKE_CURRENT_SOURCE_DIR}" "${_source}") 12 | else() 13 | set(_source_rel "${_source}") 14 | endif() 15 | get_filename_component(_source_path "${_source_rel}" PATH) 16 | string(REPLACE "/" "\\" _source_path_msvc "${_source_path}") 17 | source_group("${_source_path_msvc}" FILES "${_source}") 18 | endforeach() 19 | endfunction() 20 | 21 | function(overlook_add_executable) 22 | if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin)$") 23 | foreach(_source IN ITEMS ${ARGN}) 24 | assign_source_group(${_source}) 25 | endforeach() 26 | #message("${ARGV}") 27 | endif () 28 | add_executable(${ARGV}) 29 | endfunction() 30 | 31 | function(overlook_cuda_add_executable) 32 | if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin)$") 33 | foreach(_source IN ITEMS ${ARGN}) 34 | assign_source_group(${_source}) 35 | endforeach() 36 | #message("${ARGV}") 37 | endif () 38 | cuda_add_executable(${ARGV}) 39 | endfunction(overlook_cuda_add_executable) 40 | 41 | function(overlook_add_library) 42 | if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin)$") 43 | foreach(_source IN ITEMS ${ARGN}) 44 | assign_source_group(${_source}) 45 | endforeach() 46 | #message("${ARGV}") 47 | endif () 48 | add_library(${ARGV}) 49 | endfunction() 50 | 51 | function(overlook_cuda_add_library) 52 | if(CMAKE_SYSTEM_NAME MATCHES "^(Windows|Darwin)$") 53 | foreach(_source IN ITEMS ${ARGN}) 54 | assign_source_group(${_source}) 55 | endforeach() 56 | #message("${ARGV}") 57 | endif () 58 | cuda_add_library(${ARGV}) 59 | endfunction() -------------------------------------------------------------------------------- /plugins/summary.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-05-26 23:30:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | set(SUMMARY_VERSION "2024-06-12 00:00:00") 8 | 9 | message("================================================================================") 10 | message(" CMake Configure Summary ") 11 | message("--------------------------------------------------------------------------------") 12 | message(" Author: Zhuo Zhang (imzhuo#foxmail.com)") 13 | message(" Version: ${SUMMARY_VERSION}") 14 | message(" Usage: include(summary.cmake) # put in bottom of Root CMakeLists.txt") 15 | message("================================================================================") 16 | 17 | #------------------------------ 18 | # CMake information 19 | #------------------------------ 20 | message("CMake Information:") 21 | message(" - CMake Version: ${CMAKE_VERSION}") 22 | message(" - CMake Generator: ${CMAKE_GENERATOR}") 23 | message(" - CMake Building Tools: ${CMAKE_BUILD_TOOL}") 24 | message(" - Target System: ${CMAKE_SYSTEM_NAME}") 25 | message("") 26 | 27 | #------------------------------ 28 | # C/C++ Compiler Information 29 | #------------------------------ 30 | message("Toolchain Information:") 31 | message(" Cross Compiling: ${CMAKE_CROSSCOMPILING}") 32 | message(" C/C++ Compiler:") 33 | message(" - C standard version: C${CMAKE_C_STANDARD}") 34 | message(" - C standard required: ${CMAKE_C_STANDARD_REQUIRED}") 35 | message(" - C standard extensions: ${CMAKE_C_EXTENSIONS}") 36 | message(" - C compiler version: ${CMAKE_C_COMPILER_VERSION}") 37 | message(" - C compiler: ${CMAKE_C_COMPILER}") 38 | message(" - C++ standard version: C++${CMAKE_CXX_STANDARD}") 39 | message(" - C++ standard required: ${CMAKE_CXX_STANDARD_REQUIRED}") 40 | message(" - C++ standard extensions: ${CMAKE_CXX_EXTENSIONS}") 41 | message(" - C++ compiler version: ${CMAKE_CXX_COMPILER_VERSION}") 42 | message(" - C++ compiler: ${CMAKE_CXX_COMPILER}") 43 | message("") 44 | 45 | #------------------------------ 46 | # C/C++ Compilation Information 47 | #------------------------------ 48 | string(TOUPPER "${CMAKE_BUILD_TYPE}" capitalized_build_type) 49 | 50 | message("C/C++ Compilation Information") 51 | message(" - CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 52 | message(" - CONFIG: ${capitalized_build_type}") 53 | message(" - CMAKE_CXX_FLAGS(for all build types): ${CMAKE_CXX_FLAGS}") 54 | set(summary_cxx_flags "${CMAKE_CXX_FLAGS}") 55 | 56 | if(NOT (CMAKE_BUILD_TYPE EQUAL "None" OR NOT CMAKE_BUILD_TYPE)) 57 | message(" - CMAKE_CXX_FLAGS_: CMAKE_CXX_FLAGS_${capitalized_build_type} : ${CMAKE_CXX_FLAGS_${capitalized_build_type}}") 58 | set(summary_cxx_flags "${summary_cxx_flags} ${CMAKE_CXX_FLAGS_${capitalized_build_type}}") 59 | endif() 60 | 61 | # e.g. -Werror=return-type 62 | get_directory_property(summary_detected_global_compile_options COMPILE_OPTIONS) 63 | message(" - Global Compile Options(via `add_compile_options()`): ${summary_detected_global_compile_options}") 64 | set(summary_cxx_flags "${summary_cxx_flags} ${summary_detected_global_compile_options}") 65 | 66 | # e.g. -I/some/dir 67 | get_directory_property(summary_detected_global_include_directories INCLUDE_DIRECTORIES) 68 | set(styled_global_include_directories "") 69 | foreach(include_directory ${summary_detected_global_include_directories}) 70 | set(styled_global_include_directories "-I${include_directory} ${styled_global_include_directories}") 71 | endforeach() 72 | set(summary_cxx_flags "${styled_global_include_directories} ${summary_cxx_flags}") 73 | message(" - Global Include Directories(via `include_directories()`): ${summary_detected_global_include_directories}") 74 | 75 | # e.g. -Dfoo=123 76 | get_directory_property(summary_detected_global_compile_definitions COMPILE_DEFINITIONS) 77 | set(styled_global_compile_definitions "") 78 | foreach(compile_definition ${summary_detected_global_compile_definitions}) 79 | #message("-D${compile_definition}") 80 | set(styled_global_compile_definitions "-D${compile_definition} ${styled_global_compile_definitions}") 81 | endforeach() 82 | set(summary_cxx_flags "${styled_global_compile_definitions} ${summary_cxx_flags}") 83 | message(" - Global Compile Definitions: ${styled_global_compile_definitions}") 84 | message(" (via `add_compile_definitions()`, `add_definitions()`)") 85 | 86 | message(" - Final CXX FLAGS: ${summary_cxx_flags}") 87 | message(" (which consists of {add_compile_definitions(), CMAKE_CXX_FLAGS, CMAKE_CXX_FLAGS_, add_compile_options()}") 88 | message(" See ${CMAKE_BINARY_DIR}/compile_commands.json for full details") 89 | message("") 90 | 91 | #------------------------------ 92 | # C/C++ Linking Information 93 | #------------------------------ 94 | message("C/C++ Linking Information") 95 | # e.g. -L/some/dir 96 | get_directory_property(summary_detected_global_link_directories LINK_DIRECTORIES) 97 | message(" - Global Link Directories(via `link_directories()`): ${summary_detected_global_link_directories}") 98 | 99 | # e.g. -llibname 100 | get_directory_property(summary_detected_global_link_options LINK_OPTIONS) 101 | message(" - Global Link Options(via `add_link_options()`): ${summary_detected_global_link_options}") 102 | 103 | message(" See ${CMAKE_BINARY_DIR}/CMakeFiles/\${target_name}.dir/link.txt) for full details") 104 | message("") 105 | 106 | #------------------------------ 107 | # Target list 108 | #------------------------------ 109 | function(summary_get_all_targets var) 110 | set(targets) 111 | summary_get_all_targets_recursive(targets ${CMAKE_CURRENT_SOURCE_DIR}) 112 | set(${var} ${targets} PARENT_SCOPE) 113 | endfunction() 114 | 115 | macro(summary_get_all_targets_recursive targets dir) 116 | get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES) 117 | foreach(subdir ${subdirectories}) 118 | summary_get_all_targets_recursive(${targets} ${subdir}) 119 | endforeach() 120 | 121 | get_property(current_targets DIRECTORY ${dir} PROPERTY BUILDSYSTEM_TARGETS) 122 | list(APPEND ${targets} ${current_targets}) 123 | endmacro() 124 | 125 | summary_get_all_targets(all_targets) 126 | message("List of targets (name, type, link command file):") 127 | foreach(target_name ${all_targets}) 128 | get_target_property(target_type ${target_name} TYPE) 129 | message(" ${target_name}") 130 | message(" - target type: ${target_type}") 131 | 132 | get_property(tgt_binary_dir TARGET ${target_name} PROPERTY BINARY_DIR) 133 | message(" - binary dir: ${tgt_binary_dir}") 134 | 135 | if(${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") 136 | message(" - link command: ${tgt_binary_dir}/CMakeFiles/${target_name}.dir/link.txt") 137 | elseif(${CMAKE_GENERATOR} STREQUAL "Ninja") 138 | message(" - link command: ${CMAKE_BINARY_DIR}/build.ninja") 139 | endif() 140 | 141 | get_property(tgt_compile_flags TARGET ${target_name} PROPERTY COMPILE_FLAGS) 142 | if(tgt_compile_flags) 143 | message(" - compile flags: ${tgt_compile_flags}") 144 | endif() 145 | 146 | get_property(tgt_compile_options TARGET ${target_name} PROPERTY COMPILE_OPTIONS) 147 | if(tgt_compile_options) 148 | message(" - compile options: ${tgt_compile_options}") 149 | endif() 150 | 151 | get_property(tgt_compile_definitions TARGET ${target_name} PROPERTY COMPILE_DEFINITIONS) 152 | if(tgt_compile_definitions) 153 | message(" - compile definitions: ${tgt_compile_definitions}") 154 | endif() 155 | 156 | get_property(tgt_link_options TARGET ${target_name} PROPERTY LINK_OPTIONS) 157 | if(tgt_link_options) 158 | message(" - link options: ${tgt_link_options}") 159 | endif() 160 | 161 | get_property(tgt_link_flags TARGET ${target_name} PROPERTY LINK_FLAGS) 162 | if(tgt_link_flags) 163 | message(" - link flags: ${tgt_link_flags}") 164 | endif() 165 | endforeach() 166 | message("") 167 | 168 | 169 | #------------------------------ 170 | # Misc stuffs 171 | #------------------------------ 172 | message("Misc Information:") 173 | # show building install path 174 | message(" Package install path: ${CMAKE_INSTALL_PREFIX}") 175 | message("") 176 | 177 | message(" OpenMP:") 178 | if(OpenMP_FOUND) 179 | message(" - OpenMP was found: YES") 180 | message(" - OpenMP version: ${OpenMP_C_VERSION}") 181 | else() 182 | message(" - OpenMP was found: NO") 183 | endif() 184 | message("") 185 | 186 | -------------------------------------------------------------------------------- /plugins/tsan.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | # Last update: 2024-06-13 22:14:00 4 | cmake_minimum_required(VERSION 3.15) 5 | include_guard() 6 | 7 | add_compile_options( 8 | "$<$:-fsanitize=thread;-fno-omit-frame-pointer;-g>" 9 | "$<$:-fsanitize=thread;-fno-omit-frame-pointer;-g>" 10 | ) 11 | add_link_options( 12 | "$<$:-fsanitize=thread>" 13 | "$<$:-fsanitize=thread>" 14 | ) 15 | -------------------------------------------------------------------------------- /rocbuild.cmake: -------------------------------------------------------------------------------- 1 | # Author: Zhuo Zhang 2 | # Homepage: https://github.com/zchrissirhcz/rocbuild 3 | 4 | cmake_minimum_required(VERSION 3.13) 5 | 6 | # CMake 3.10: include_guard() 7 | # CMake 3.21: $ 8 | # CMake 3.13: target_link_options() use "LINKER:" as a portable way for different compiler + linker combo 9 | 10 | include_guard() 11 | 12 | 13 | macro(rocbuild_set_artifacts_path) 14 | if(NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) 15 | # Where add_executable() generates executable file 16 | # Where add_library(SHARED) generates .dll file on Windowos 17 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "") 18 | endif() 19 | 20 | if(NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) 21 | # Where add_library(MODULE) generates loadable module file (.dll or .so) 22 | # Where add_library(SHARED) generates shared library (.so, .dylib) 23 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "") 24 | endif() 25 | 26 | if(NOT CMAKE_ARCHIVE_OUTPUT_DIRECTORY) 27 | # Where add_library(STATIC) generates static library file 28 | # Where add_library(SHARED) generates the import library file (.lib) of the shared library (.dll) if exports at least one symbol 29 | # Where add_executable() generates the import library file (.lib) of the executable target if ENABLE_EXPORTS target property is set 30 | # Where add_executable() generates the linker import file (.imp on AIX) of the executable target if ENABLE_EXPORTS target property is set 31 | # Where add_library(SHARED) generates the linker import file (.tbd) of the shared library target if ENABLE_EXPORTS target property is set 32 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE INTERNAL "") 33 | endif() 34 | endmacro() 35 | 36 | 37 | macro(rocbuild_enable_ninja_colorful_output) 38 | # When building a CMake-based project, Ninja may speedup the building speed, comparing to Make. 39 | # However, with `-GNinja` specified, compile errors are with no obvious colors. 40 | # This cmake plugin just solve this mentioned problem, giving colorful output for Ninja. 41 | ## References: https://medium.com/@alasher/colored-c-compiler-output-with-ninja-clang-gcc-10bfe7f2b949 42 | add_compile_options( 43 | "$<$:-fdiagnostics-color=always>" 44 | "$<$:-fcolor-diagnostics>" 45 | "$<$:-fdiagnostics-color=always>" 46 | "$<$:-fcolor-diagnostics>" 47 | ) 48 | endmacro() 49 | 50 | 51 | # Transitively list all link libraries of a target (recursive call) 52 | # Modified from https://github.com/libigl/libigl/blob/main/cmake/igl/igl_copy_dll.cmake, GPL-3.0 / MPL-2.0 53 | function(rocbuild_get_target_dependencies_impl OUTPUT_VARIABLE TARGET) 54 | get_target_property(_aliased ${TARGET} ALIASED_TARGET) 55 | if(_aliased) 56 | set(TARGET ${_aliased}) 57 | endif() 58 | 59 | get_target_property(_IMPORTED ${TARGET} IMPORTED) 60 | get_target_property(_TYPE ${TARGET} TYPE) 61 | if(_IMPORTED OR (${_TYPE} STREQUAL "INTERFACE_LIBRARY")) 62 | get_target_property(TARGET_DEPENDENCIES ${TARGET} INTERFACE_LINK_LIBRARIES) 63 | else() 64 | get_target_property(TARGET_DEPENDENCIES ${TARGET} LINK_LIBRARIES) 65 | endif() 66 | 67 | set(VISITED_TARGETS ${${OUTPUT_VARIABLE}}) 68 | foreach(DEPENDENCY IN ITEMS ${TARGET_DEPENDENCIES}) 69 | if(TARGET ${DEPENDENCY}) 70 | get_target_property(_aliased ${DEPENDENCY} ALIASED_TARGET) 71 | if(_aliased) 72 | set(DEPENDENCY ${_aliased}) 73 | endif() 74 | 75 | if(NOT (DEPENDENCY IN_LIST VISITED_TARGETS)) 76 | list(APPEND VISITED_TARGETS ${DEPENDENCY}) 77 | rocbuild_get_target_dependencies_impl(VISITED_TARGETS ${DEPENDENCY}) 78 | endif() 79 | endif() 80 | endforeach() 81 | set(${OUTPUT_VARIABLE} ${VISITED_TARGETS} PARENT_SCOPE) 82 | endfunction() 83 | 84 | # Transitively list all link libraries of a target 85 | function(rocbuild_get_target_dependencies OUTPUT_VARIABLE TARGET) 86 | set(DISCOVERED_TARGETS "") 87 | rocbuild_get_target_dependencies_impl(DISCOVERED_TARGETS ${TARGET}) 88 | set(${OUTPUT_VARIABLE} ${DISCOVERED_TARGETS} PARENT_SCOPE) 89 | endfunction() 90 | 91 | # Copy .dll dependencies to a target executable's folder. This function must be called *after* all the CMake 92 | # dependencies of the executable target have been defined, otherwise some .dlls might not be copied to the target 93 | # folder. 94 | function(rocbuild_copy_dlls target) 95 | # Sanity checks 96 | if(CMAKE_CROSSCOMPILING OR (NOT WIN32)) 97 | return() 98 | endif() 99 | 100 | if(NOT TARGET ${target}) 101 | message(STATUS "rocbuild_copy_dlls() was called with a non-target: ${target}") 102 | return() 103 | endif() 104 | 105 | # Sanity checks 106 | get_target_property(TYPE ${target} TYPE) 107 | if(NOT ${TYPE} STREQUAL "EXECUTABLE") 108 | message(FATAL_ERROR "rocbuild_copy_dlls() was called on a non-executable target: ${target}") 109 | endif() 110 | 111 | if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.21") 112 | add_custom_command(TARGET ${target} POST_BUILD 113 | COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ 114 | COMMAND_EXPAND_LISTS 115 | ) 116 | return() 117 | endif() 118 | 119 | # set the name of file to be written 120 | if(DEFINED CMAKE_CONFIGURATION_TYPES) 121 | set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_dlls_${target}_$.cmake") 122 | else() 123 | set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_dlls_${target}.cmake") 124 | endif() 125 | 126 | add_custom_command( 127 | TARGET ${target} 128 | PRE_LINK 129 | COMMAND ${CMAKE_COMMAND} -E touch "${COPY_SCRIPT}" 130 | COMMAND ${CMAKE_COMMAND} -P "${COPY_SCRIPT}" 131 | COMMENT "Copying dlls for target ${target}" 132 | ) 133 | 134 | # Retrieve all target dependencies 135 | rocbuild_get_target_dependencies(TARGET_DEPENDENCIES ${target}) 136 | 137 | set(DEPENDENCY_FILES "") 138 | foreach(DEPENDENCY IN LISTS TARGET_DEPENDENCIES) 139 | get_target_property(TYPE ${DEPENDENCY} TYPE) 140 | if(NOT (${TYPE} STREQUAL "SHARED_LIBRARY" OR ${TYPE} STREQUAL "MODULE_LIBRARY")) 141 | continue() 142 | endif() 143 | string(APPEND DEPENDENCY_FILES " $ # ${DEPENDENCY}\n") 144 | endforeach() 145 | 146 | set(COPY_SCRIPT_CONTENT "") 147 | string(APPEND COPY_SCRIPT_CONTENT 148 | "set(dependency_files \n${DEPENDENCY_FILES})\n\n" 149 | "list(REMOVE_DUPLICATES dependency_files)\n\n" 150 | "foreach(file IN ITEMS \${dependency_files})\n" 151 | " if(EXISTS \"\${file}\")\n " 152 | "execute_process(COMMAND \${CMAKE_COMMAND} -E copy_if_different " 153 | "\"\${file}\" \"$/\")\n" 154 | " endif()\n" 155 | ) 156 | string(APPEND COPY_SCRIPT_CONTENT "endforeach()\n") 157 | 158 | # Finally generate one script for each configuration supported by this generator 159 | message(STATUS "Populating copy rules for target: ${target}") 160 | file(GENERATE 161 | OUTPUT "${COPY_SCRIPT}" 162 | CONTENT "${COPY_SCRIPT_CONTENT}" 163 | ) 164 | endfunction() 165 | 166 | 167 | # Scan opencv_videoio dlls and copy them to the target executable's folder 168 | function(rocbuild_copy_opencv_videoio_plugin_dlls target) 169 | # Sanity checks 170 | if(CMAKE_CROSSCOMPILING OR (NOT WIN32)) 171 | return() 172 | endif() 173 | 174 | if(NOT TARGET ${target}) 175 | message(WARNING "rocbuild_copy_opencv_videoio_plugin_dlls() was called with a non-target: ${target}") 176 | return() 177 | endif() 178 | 179 | get_target_property(TYPE ${target} TYPE) 180 | if(NOT ${TYPE} STREQUAL "EXECUTABLE") 181 | message(WARNING "rocbuild_copy_opencv_videoio_plugin_dlls() was called on a non-executable target: ${target}") 182 | return() 183 | endif() 184 | 185 | # If OpenCV_DIR is not set, we can't copy the opencv_videoio dlls 186 | if(NOT DEFINED OpenCV_DIR) 187 | message(WARNING "OpenCV_DIR is not defined, can't copy opencv_videoio dlls") 188 | return() 189 | endif() 190 | 191 | if(DEFINED CMAKE_CONFIGURATION_TYPES) 192 | set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_opencv_videoio_plugin_dlls_${target}_$.cmake") 193 | else() 194 | set(COPY_SCRIPT "${CMAKE_BINARY_DIR}/rocbuild_copy_opencv_videoio_plugin_dlls_${target}.cmake") 195 | endif() 196 | set(COPY_SCRIPT_CONTENT "") 197 | 198 | if(EXISTS "${OpenCV_DIR}/bin") 199 | set(opencv_videoio_plugin_dll_dir "${OpenCV_DIR}/bin") 200 | elseif(EXISTS "${OpenCV_DIR}/../bin") 201 | set(opencv_videoio_plugin_dll_dir "${OpenCV_DIR}/../bin") 202 | else() 203 | message(WARNING "Could not find opencv videoio plugin dlls in ${OpenCV_DIR}/bin or ${OpenCV_DIR}/../bin") 204 | return() 205 | endif() 206 | 207 | file(REAL_PATH "${opencv_videoio_plugin_dll_dir}" opencv_videoio_plugin_dll_dir) 208 | file(GLOB opencv_videoio_plugin_dlls "${opencv_videoio_plugin_dll_dir}/opencv_videoio_*.dll") 209 | 210 | # convert opencv_videoio_dlls to a string 211 | string(REPLACE ";" "\n" opencv_videoio_plugin_dlls "${opencv_videoio_plugin_dlls}") 212 | 213 | string(APPEND COPY_SCRIPT_CONTENT 214 | "set(opencv_videoio_plugin_dlls\n${opencv_videoio_plugin_dlls}\n)\n" 215 | "foreach(file IN ITEMS \${opencv_videoio_plugin_dlls})\n" 216 | " if(EXISTS \"\${file}\")\n" 217 | " execute_process(COMMAND \${CMAKE_COMMAND} -E copy_if_different \"\${file}\" \"$\")\n" 218 | " endif()\n" 219 | "endforeach()\n" 220 | ) 221 | 222 | file(GENERATE 223 | OUTPUT "${COPY_SCRIPT}" 224 | CONTENT "${COPY_SCRIPT_CONTENT}" 225 | ) 226 | 227 | add_custom_command( 228 | TARGET ${target} 229 | PRE_LINK 230 | COMMAND ${CMAKE_COMMAND} -E touch "${COPY_SCRIPT}" 231 | COMMAND ${CMAKE_COMMAND} -P "${COPY_SCRIPT}" 232 | COMMENT "Copying opencv_videoio plugin dlls for target ${target}" 233 | ) 234 | endfunction() 235 | 236 | 237 | function(rocbuild_set_debug_postfix TARGET) 238 | # determine TARGET type 239 | get_target_property(TYPE ${TARGET} TYPE) 240 | if(NOT TYPE) 241 | message(FATAL_ERROR "rocbuild_set_debug_postfix() called with non-existent target: ${TARGET}") 242 | endif() 243 | 244 | # determine if TARGET is imported 245 | get_target_property(IMPORTED ${TARGET} IMPORTED) 246 | if(IMPORTED) 247 | return() 248 | endif() 249 | 250 | # Don't treat for single config generators 251 | if(NOT CMAKE_CONFIGURATION_TYPES) 252 | return() 253 | endif() 254 | 255 | if(TYPE MATCHES "^(STATIC_LIBRARY|SHARED_LIBRARY|EXECUTABLE)$") 256 | set_target_properties(${TARGET} PROPERTIES DEBUG_POSTFIX "_d") 257 | endif() 258 | endfunction() 259 | 260 | 261 | function(rocbuild_hide_symbols TARGET) 262 | get_target_property(TARGET_TYPE ${TARGET} TYPE) 263 | if(TARGET_TYPE STREQUAL "SHARED_LIBRARY") 264 | if((CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") OR 265 | (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")) 266 | target_compile_options(${TARGET} PRIVATE "-fvisibility=hidden") 267 | endif() 268 | endif() 269 | endfunction() 270 | 271 | 272 | function(rocbuild_link_as_needed TARGET) 273 | get_target_property(TARGET_TYPE ${TARGET} TYPE) 274 | if(TARGET_TYPE STREQUAL "SHARED_LIBRARY") 275 | if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") OR 276 | (CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")) 277 | target_link_options(${TARGET} PRIVATE "LINKER:-as-needed") 278 | elseif((CMAKE_C_COMPILER_ID STREQUAL "AppleClang") OR 279 | (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")) 280 | target_link_options(${TARGET} PRIVATE "LINKER:-dead_strip_dylibs") 281 | endif() 282 | endif() 283 | endfunction() 284 | 285 | 286 | function(rocbuild_remove_unused_data_and_function TARGET) 287 | if(CMAKE_BUILD_TYPE STREQUAL "Release" OR "$") 288 | if((CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") OR 289 | (CMAKE_CXX_COMPILER_ID MATCHES "^(GNU|Clang)$")) 290 | target_compile_options(${TARGET} PRIVATE "-fdata-sections" "-ffunction-sections") 291 | target_link_options(${TARGET} PRIVATE "LINKER:--gc-sections") 292 | elseif((CMAKE_C_COMPILER_ID STREQUAL "AppleClang") OR 293 | (CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")) 294 | target_compile_options(${TARGET} PRIVATE "-fdata-sections" "-ffunction-sections") 295 | target_link_options(${TARGET} PRIVATE "LINKER:-dead_strip") 296 | endif() 297 | endif() 298 | endfunction() 299 | 300 | 301 | function(rocbuild_print_args) 302 | message(STATUS "ROCBUILD/I: CMake version: ${CMAKE_VERSION}") 303 | message(STATUS "ROCBUILD/I: ROCBUILD_PLATFORM: ${ROCBUILD_PLATFORM}") 304 | message(STATUS "ROCBUILD/I: ROCBUILD_ARCH: ${ROCBUILD_ARCH}") 305 | endfunction() 306 | 307 | 308 | function(rocbuild_is_asan_available OUTPUT_VARIABLE) 309 | if((CMAKE_C_COMPILER_ID MATCHES "GNU|Clang") OR (CMAKE_CXX_COMPILER_ID STREQUAL "GNU|Clang")) 310 | set(${OUTPUT_VARIABLE} TRUE PARENT_SCOPE) 311 | elseif(MSVC) 312 | if(CMAKE_C_COMPILER_VERSION STRLESS 16.7 OR CMAKE_CXX_COMPILER_VERSION STRLESS 16.7) 313 | set(${OUTPUT_VARIABLE} FALSE PARENT_SCOPE) 314 | message(WARNING "ASAN is available since VS2019 16.7, but you are using ${CMAKE_C_COMPILER_VERSION}") 315 | else() 316 | set(${OUTPUT_VARIABLE} TRUE PARENT_SCOPE) 317 | endif() 318 | else() 319 | set(${OUTPUT_VARIABLE} FALSE PARENT_SCOPE) 320 | endif() 321 | endfunction() 322 | 323 | 324 | function(rocbuild_enable_asan TARGET) 325 | rocbuild_is_asan_available(ASAN_AVAILABLE) 326 | if(NOT ASAN_AVAILABLE) 327 | message(WARNING "ASAN is not available for the current compiler") 328 | return() 329 | endif() 330 | 331 | # Retrieve all target dependencies 332 | rocbuild_get_target_dependencies(TARGETS_TO_PROCESS ${TARGET}) 333 | 334 | if(MSVC) 335 | set(ASAN_COMPILE_OPTIONS /fsanitize=address) 336 | set(ASAN_LINK_OPTIONS /ignore:4300) # /INCREMENTAL 337 | else() 338 | set(ASAN_COMPILE_OPTIONS -fsanitize=address -fno-omit-frame-pointer -g) 339 | set(ASAN_LINK_OPTIONS -fsanitize=address) 340 | endif() 341 | 342 | # Add TARGET itself to the list of targets to process 343 | list(APPEND TARGETS_TO_PROCESS ${TARGET}) 344 | 345 | foreach(DEPENDENCY IN LISTS TARGETS_TO_PROCESS) 346 | # Skip imported targets 347 | get_target_property(IMPORTED ${DEPENDENCY} IMPORTED) 348 | if(IMPORTED) 349 | continue() 350 | endif() 351 | 352 | get_target_property(TYPE ${DEPENDENCY} TYPE) 353 | if(TYPE STREQUAL "INTERFACE_LIBRARY") 354 | target_compile_options(${DEPENDENCY} INTERFACE ${ASAN_COMPILE_OPTIONS}) 355 | target_link_options(${DEPENDENCY} INTERFACE ${ASAN_LINK_OPTIONS}) 356 | else() 357 | target_compile_options(${DEPENDENCY} PUBLIC ${ASAN_COMPILE_OPTIONS}) 358 | target_link_options(${DEPENDENCY} PUBLIC ${ASAN_LINK_OPTIONS}) 359 | endif() 360 | endforeach() 361 | endfunction() 362 | 363 | 364 | # Should be called after rocbuild_enable_asan() 365 | function(rocbuild_set_vs_debugger_environment TARGET) 366 | # Skip non-Visual Studio generators 367 | if(NOT CMAKE_GENERATOR MATCHES "Visual Studio") 368 | return() 369 | endif() 370 | 371 | # Skip non-executable targets 372 | get_target_property(TARGET_TYPE ${TARGET} TYPE) 373 | if(NOT TARGET_TYPE STREQUAL "EXECUTABLE") 374 | return() 375 | endif() 376 | 377 | set(EXTRA_PATHS) 378 | set(EXTRA_VARS) 379 | if(CMAKE_C_COMPILER_ID STREQUAL "MSVC" OR CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") 380 | # Check if TARGET is with ASAN enabled 381 | get_target_property(TARGET_COMPILE_OPTIONS ${TARGET} COMPILE_OPTIONS) 382 | if(TARGET_COMPILE_OPTIONS MATCHES "/fsanitize=address") 383 | # https://devblogs.microsoft.com/cppblog/msvc-address-sanitizer-one-dll-for-all-runtime-configurations/ 384 | if((CMAKE_C_COMPILER_VERSION STRGREATER_EQUAL 17.7) OR (CMAKE_CXX_COMPILER_ID STRGREATER_EQUAL 17.7)) 385 | if(CMAKE_GENERATOR_PLATFORM MATCHES "x64") 386 | list(APPEND EXTRA_PATHS "$(VC_ExecutablePath_x64)") 387 | list(APPEND EXTRA_VARS "ASAN_SYMBOLIZER_PATH=$(VC_ExecutablePath_x64)") 388 | elseif(CMAKE_GENERATOR_PLATFORM MATCHES "Win32") 389 | list(APPEND EXTRA_PATHS "$(VC_ExecutablePath_x86)") 390 | list(APPEND EXTRA_VARS "ASAN_SYMBOLIZER_PATH=$(VC_ExecutablePath_x86)") 391 | endif() 392 | endif() 393 | endif() 394 | endif() 395 | 396 | # Retrieve all target dependencies 397 | rocbuild_get_target_dependencies(TARGET_DEPENDENCIES ${TARGET}) 398 | foreach(DEPENDENCY IN LISTS TARGET_DEPENDENCIES) 399 | get_target_property(TYPE ${DEPENDENCY} TYPE) 400 | if(TYPE STREQUAL "SHARED_LIBRARY") 401 | set(DLL_DIRECTORY $) 402 | list(APPEND EXTRA_PATHS ${DLL_DIRECTORY}) 403 | endif() 404 | endforeach() 405 | 406 | set(VS_DEBUGGER_ENVIRONMENT "PATH=${EXTRA_PATHS};%PATH%") 407 | if(EXTRA_VARS) 408 | string(APPEND VS_DEBUGGER_ENVIRONMENT "\n") 409 | string(APPEND VS_DEBUGGER_ENVIRONMENT "${EXTRA_VARS}") 410 | endif() 411 | 412 | set_target_properties(${TARGET} PROPERTIES VS_DEBUGGER_ENVIRONMENT "${VS_DEBUGGER_ENVIRONMENT}") 413 | endfunction() 414 | 415 | 416 | macro(rocbuild_import_package RECIPE) 417 | # Parse attributes from recipe 418 | string(REGEX MATCH "^([^/]+)/(.+)$" _ "${RECIPE}") 419 | set(pkg_name ${CMAKE_MATCH_1}) 420 | set(pkg_version ${CMAKE_MATCH_2}) 421 | 422 | message(STATUS "[debug] package name: ${pkg_name}") 423 | message(STATUS "[debug] package version: ${pkg_version}") 424 | 425 | set(pkg_dir ".rocpkg/${pkg_name}-${pkg_version}") 426 | if(NOT EXISTS ${pkg_dir}) 427 | message(FATAL_ERROR "${pkg_dir} not exist. \nPlease run: python rocpkg.py install ${RECIPE}") 428 | endif() 429 | 430 | add_library(${pkg_name} INTERFACE) 431 | target_include_directories(${pkg_name} 432 | INTERFACE 433 | ${pkg_dir} 434 | ) 435 | set_target_properties(${pkg_name} PROPERTIES 436 | VERSION ${pkg_version} 437 | INTERFACE_${pkg_name}_VERSION "${pkg_version}" 438 | ) 439 | 440 | # cleanup 441 | unset(pkg_name) 442 | unset(pkg_version) 443 | unset(pkg_dir) 444 | endmacro() 445 | 446 | 447 | rocbuild_print_args() 448 | rocbuild_set_artifacts_path() 449 | rocbuild_enable_ninja_colorful_output() -------------------------------------------------------------------------------- /rocpkg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import sys 4 | import subprocess 5 | from pathlib import Path 6 | 7 | PKG_REPO = "/Users/zz/play/pkgs" 8 | 9 | def install_package(recipe: str): 10 | """ 11 | @param recipe: / 12 | e.g. CLI11/2.3.2 13 | """ 14 | 15 | rocpkg_dir = Path('.rocpkg') 16 | rocpkg_dir.mkdir(exist_ok=True) 17 | 18 | pkg_name, pkg_version = recipe.split('/') 19 | install_cmd = f'git clone {PKG_REPO} -b {pkg_name}/{pkg_version} .rocpkg/{pkg_name}-{pkg_version}' 20 | 21 | print(f'[debug] install cmd: {install_cmd}') 22 | 23 | try: 24 | subprocess.run(install_cmd, shell=True, check=True) 25 | print(f'[info] success {recipe}') 26 | except subprocess.CalledProcessError as e: 27 | print(f'[error] failed: {e}', file=sys.stderr) 28 | sys.exit(1) 29 | 30 | def main(): 31 | if len(sys.argv) < 3: 32 | print('Usage: rocpkg install <包名>/<版本号>') 33 | print('e.g.: rocpkg install CLI11/2.4.2') 34 | sys.exit(1) 35 | 36 | command = sys.argv[1] 37 | if command != 'install': 38 | print(f'[error] unknown command: {command}') 39 | sys.exit(1) 40 | 41 | recipe = sys.argv[2] 42 | if '/' not in recipe: 43 | print('[error] failed to parse recipe. format: /') 44 | sys.exit(1) 45 | 46 | install_package(recipe) 47 | 48 | def examples(): 49 | install_package("CLI11/2.3.2") 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /rocsetup.cmake: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | function(print_args) 4 | math(EXPR LAST_INDEX "${CMAKE_ARGC}-1") 5 | foreach(i RANGE 1 ${LAST_INDEX}) 6 | message("Argument ${i}: ${CMAKE_ARGV${i}}") 7 | endforeach() 8 | endfunction() 9 | 10 | 11 | function(print_original_args) 12 | set(all_args) 13 | foreach(i RANGE 0 ${CMAKE_ARGC}) 14 | set(all_args "${all_args} ${CMAKE_ARGV${i}}") 15 | endforeach() 16 | message(STATUS "ROCSETUP/I: Raw command:${all_args}") 17 | endfunction() 18 | 19 | 20 | function(parse_args) 21 | math(EXPR LAST_INDEX "${CMAKE_ARGC}-1") 22 | set(options -p -a -S -B) 23 | set(current_option "") 24 | foreach(i RANGE 1 ${LAST_INDEX}) 25 | # message("Argument ${i}: ${CMAKE_ARGV${i}}") 26 | set(arg "${CMAKE_ARGV${i}}") 27 | if(${arg} IN_LIST options) 28 | set(current_option "${arg}") 29 | else() 30 | if(current_option STREQUAL "-p") 31 | set(ROCBUILD_PLATFORM "${arg}" PARENT_SCOPE) 32 | elseif(current_option STREQUAL "-a") 33 | set(ROCBUILD_ARCH "${arg}" PARENT_SCOPE) 34 | elseif(current_option STREQUAL "-S") 35 | set(ROCBUILD_SOURCE_DIR "${arg}" PARENT_SCOPE) 36 | elseif(current_option STREQUAL "-B") 37 | set(ROCBUILD_BINARY_DIR "${arg}" PARENT_SCOPE) 38 | endif() 39 | set(current_option "") 40 | endif() 41 | endforeach() 42 | endfunction() 43 | 44 | function(set_generator) 45 | if(ROCBUILD_PLATFORM STREQUAL "vs2022") 46 | set(ROCBUILD_GENERATOR "Visual Studio 17 2022") 47 | elseif(ROCBUILD_ARCH STREQUAL "vs2019") 48 | set(ROCBUILD_GENERATOR "Visual Studio 16 2019") 49 | endif() 50 | 51 | if(ROCBUILD_GENERATOR MATCHES "Visual Studio") 52 | if(ROCBUILD_ARCH MATCHES "x64") 53 | set(ROCBUILD_GENERATOR_EXTRA -A x64) 54 | elseif(ROCBUILD_ARCH MATCHES "x86") 55 | set(ROCBUILD_GENERATOR_EXTRA -A win32) 56 | endif() 57 | endif() 58 | set(ROCBUILD_GENERATOR ${ROCBUILD_GENERATOR} PARENT_SCOPE) 59 | set(ROCBUILD_GENERATOR_EXTRA ${ROCBUILD_GENERATOR_EXTRA} PARENT_SCOPE) 60 | endfunction() 61 | 62 | 63 | if(NOT DEFINED CMAKE_SCRIPT_MODE_FILE) 64 | message(FATAL_ERROR "rocsetup.cmake can only be used in script mode, i.e. cmake -P rocsetup.cmake ...") 65 | return() 66 | endif() 67 | 68 | 69 | print_original_args() 70 | #print_args() 71 | parse_args() 72 | set_generator() 73 | 74 | set(cmake_arguments) 75 | 76 | if(ROCBUILD_SOURCE_DIR) 77 | list(APPEND cmake_arguments -S ${ROCBUILD_SOURCE_DIR}) 78 | endif() 79 | 80 | if(ROCBUILD_BINARY_DIR) 81 | list(APPEND cmake_arguments -B ${ROCBUILD_BINARY_DIR}) 82 | endif() 83 | 84 | if(ROCBUILD_GENERATOR) 85 | list(APPEND cmake_arguments -G ${ROCBUILD_GENERATOR} ${ROCBUILD_GENERATOR_EXTRA}) 86 | endif() 87 | 88 | if(ROCBUILD_PLATFORM) 89 | list(APPEND cmake_arguments -DROCBUILD_PLATFORM=${ROCBUILD_PLATFORM}) 90 | else() 91 | message(FATAL_ERROR "Platform not specified") 92 | endif() 93 | 94 | if(ROCBUILD_ARCH) 95 | list(APPEND cmake_arguments -DROCBUILD_ARCH=${ROCBUILD_ARCH}) 96 | else() 97 | message(FATAL_ERROR "Architecture not specified") 98 | endif() 99 | 100 | set(parsed_command "cmake ${cmake_arguments}") 101 | string(REPLACE ";" " " parsed_command_str "${parsed_command}") 102 | message(STATUS "ROCSETUP/I: Parsed command: ${parsed_command_str}") 103 | execute_process( 104 | COMMAND cmake ${cmake_arguments} 105 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 106 | RESULT_VARIABLE result 107 | OUTPUT_VARIABLE output 108 | ERROR_VARIABLE error_output 109 | ) 110 | 111 | if(result) 112 | message("${result}") 113 | endif() 114 | if(output) 115 | message("${output}") 116 | endif() 117 | if(error_output) 118 | message("${error_output}") 119 | endif() 120 | 121 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | import unittest 3 | import platform 4 | import shutil 5 | import os 6 | 7 | 8 | if platform.system() == 'Windows': 9 | os_name = 'windows' 10 | elif platform.system() == 'Darwin': 11 | os_name = 'mac' 12 | elif platform.system() == 'Linux': 13 | os_name = 'linux' 14 | 15 | 16 | def decode(buf): 17 | try: 18 | return buf.decode('utf-8') 19 | except: 20 | return buf.decode('cp936') 21 | 22 | 23 | def check_output(cmd): 24 | print('[cmd]', cmd) 25 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) 26 | out = p.stdout.read() 27 | p.communicate() 28 | # print(decode(out)) # debug 29 | return p.returncode, decode(out) 30 | 31 | 32 | class RocBuildTest(unittest.TestCase): 33 | 34 | def setUp(self): 35 | pass 36 | 37 | def tearDown(self): 38 | pass 39 | 40 | def check_generate(self, project_name, expected_ret=0, args=''): 41 | cmd = f'cmake -S tests/{project_name} -B build/{project_name} {args}' 42 | ret, out = check_output(cmd) 43 | self.assertEqual(expected_ret, ret, out) 44 | return out.replace('\r\n', '\n') 45 | 46 | def check_build(self, project_name, args=''): 47 | cmd = f'cmake --build build/{project_name} {args}' 48 | ret, out = check_output(cmd) 49 | self.assertEqual(0, ret, out) 50 | return out.replace('\r\n', '\n') 51 | 52 | def test_artifact_path(self): 53 | if os_name == 'windows': 54 | # determine if cl.exe is available 55 | ret, out = check_output('cl') 56 | if ret == 0: 57 | self.check_generate('artifacts_path', args='-G "Ninja Multi-Config"') 58 | self.check_build('artifacts_path', '--config Release') 59 | self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib')) 60 | self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll')) 61 | self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe')) 62 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib')) 63 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll')) 64 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe')) 65 | shutil.rmtree('build/artifacts_path') 66 | 67 | self.check_generate('artifacts_path', args="-G Ninja") 68 | self.check_build('artifacts_path', '--config Release') 69 | self.assertTrue(os.path.exists('build/artifacts_path/foo_static.lib')) 70 | self.assertTrue(os.path.exists('build/artifacts_path/foo_shared.dll')) 71 | self.assertTrue(os.path.exists('build/artifacts_path/hello.exe')) 72 | self.assertTrue(os.path.exists('build/artifacts_path/subfoo_static.lib')) 73 | self.assertTrue(os.path.exists('build/artifacts_path/subfoo_shared.dll')) 74 | self.assertTrue(os.path.exists('build/artifacts_path/subhello.exe')) 75 | shutil.rmtree('build/artifacts_path') 76 | 77 | self.check_generate('artifacts_path') 78 | self.check_build('artifacts_path', '--config Release') 79 | self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_static.lib')) 80 | self.assertTrue(os.path.exists('build/artifacts_path/Release/foo_shared.dll')) 81 | self.assertTrue(os.path.exists('build/artifacts_path/Release/hello.exe')) 82 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_static.lib')) 83 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subfoo_shared.dll')) 84 | self.assertTrue(os.path.exists('build/artifacts_path/Release/subhello.exe')) 85 | shutil.rmtree('build/artifacts_path') 86 | elif os_name == 'linux': 87 | self.check_generate('artifacts_path') 88 | self.check_build('artifacts_path') 89 | self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a')) 90 | self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.so')) 91 | self.assertTrue(os.path.exists('build/artifacts_path/hello')) 92 | self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a')) 93 | self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.so')) 94 | self.assertTrue(os.path.exists('build/artifacts_path/subhello')) 95 | shutil.rmtree('build/artifacts_path') 96 | elif os_name == 'mac': 97 | self.check_generate('artifacts_path') 98 | self.check_build('artifacts_path') 99 | self.assertTrue(os.path.exists('build/artifacts_path/libfoo_static.a')) 100 | self.assertTrue(os.path.exists('build/artifacts_path/libfoo_shared.dylib')) 101 | self.assertTrue(os.path.exists('build/artifacts_path/hello')) 102 | self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_static.a')) 103 | self.assertTrue(os.path.exists('build/artifacts_path/libsubfoo_shared.dylib')) 104 | self.assertTrue(os.path.exists('build/artifacts_path/subhello')) 105 | shutil.rmtree('build/artifacts_path') 106 | 107 | def test_debug_postfix(self): 108 | if os_name == 'windows': 109 | # msbuild 110 | self.check_generate('debug_postfix') 111 | self.check_build('debug_postfix', '--config Debug') 112 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib')) 113 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe')) 114 | shutil.rmtree('build/debug_postfix') 115 | 116 | ret, out = check_output('cl') 117 | if ret == 0: 118 | # ninja 119 | self.check_generate('debug_postfix', args='-G Ninja') 120 | self.check_build('debug_postfix') 121 | self.assertTrue(os.path.exists('build/debug_postfix/foo.lib')) 122 | self.assertTrue(os.path.exists('build/debug_postfix/hello.exe')) 123 | shutil.rmtree('build/debug_postfix') 124 | 125 | self.check_generate('debug_postfix', args='-G Ninja -DCMAKE_BUILD_TYPE=Debug') 126 | self.check_build('debug_postfix') 127 | self.assertTrue(os.path.exists('build/debug_postfix/foo.lib')) 128 | self.assertTrue(os.path.exists('build/debug_postfix/hello.exe')) 129 | shutil.rmtree('build/debug_postfix') 130 | 131 | # Ninja Multi-Config 132 | self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"') 133 | self.check_build('debug_postfix', '--config Debug') 134 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/foo_d.lib')) 135 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d.exe')) 136 | shutil.rmtree('build/debug_postfix') 137 | else: 138 | # Ninja Multi-Config 139 | self.check_generate('debug_postfix', args='-G "Ninja Multi-Config"') 140 | self.check_build('debug_postfix') 141 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/libfoo_d.a')) 142 | self.assertTrue(os.path.exists('build/debug_postfix/Debug/hello_d')) 143 | shutil.rmtree('build/debug_postfix') 144 | 145 | # make 146 | self.check_generate('debug_postfix') 147 | self.check_build('debug_postfix') 148 | self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a')) 149 | self.assertTrue(os.path.exists('build/debug_postfix/hello')) 150 | shutil.rmtree('build/debug_postfix') 151 | 152 | self.check_generate('debug_postfix', args='-DCMAKE_BUILD_TYPE=Debug') 153 | self.check_build('debug_postfix') 154 | self.assertTrue(os.path.exists('build/debug_postfix/libfoo.a')) 155 | self.assertTrue(os.path.exists('build/debug_postfix/hello')) 156 | shutil.rmtree('build/debug_postfix') 157 | 158 | def test_hide_symbols(self): 159 | if os_name == 'linux': 160 | self.check_generate('hide_symbols', args='-DHIDDEN=1') 161 | self.check_build('hide_symbols') 162 | cmd = 'nm -C build/hide_symbols/libbar.so | grep " T "' 163 | ret, out = check_output(cmd) 164 | self.assertEqual(0, ret, out) 165 | out = out.replace('\r\n', '\n') 166 | lines = out.strip().split('\n') 167 | self.assertEqual(len(lines), 1, lines) 168 | self.assertTrue(lines[0].endswith(' T bar')) 169 | shutil.rmtree('build/hide_symbols') 170 | 171 | self.check_generate('hide_symbols', args='-DHIDDEN=0') 172 | self.check_build('hide_symbols') 173 | cmd = f'nm -C build/hide_symbols/libbar.so | grep " T "' 174 | ret, out = check_output(cmd) 175 | self.assertEqual(0, ret, out) 176 | out = out.replace('\r\n', '\n') 177 | lines = out.strip().split('\n') 178 | self.assertEqual(len(lines), 2, lines) 179 | self.assertTrue(lines[0].endswith(' T bar')) 180 | self.assertTrue(lines[1].endswith(' T bar_internal')) 181 | shutil.rmtree('build/hide_symbols') 182 | elif os_name == 'mac': 183 | self.check_generate('hide_symbols', args='-DHIDDEN=1') 184 | self.check_build('hide_symbols') 185 | cmd = 'nm -C build/hide_symbols/libbar.dylib | grep " T "' 186 | ret, out = check_output(cmd) 187 | self.assertEqual(0, ret, out) 188 | out = out.replace('\r\n', '\n') 189 | lines = out.strip().split('\n') 190 | self.assertEqual(len(lines), 1, lines) 191 | self.assertTrue(lines[0].endswith(' T _bar')) 192 | shutil.rmtree('build/hide_symbols') 193 | 194 | self.check_generate('hide_symbols', args='-DHIDDEN=0') 195 | self.check_build('hide_symbols') 196 | cmd = f'nm -C build/hide_symbols/libbar.dylib | grep " T "' 197 | ret, out = check_output(cmd) 198 | self.assertEqual(0, ret, out) 199 | out = out.replace('\r\n', '\n') 200 | lines = out.strip().split('\n') 201 | self.assertEqual(len(lines), 2, lines) 202 | self.assertTrue(lines[0].endswith(' T _bar')) 203 | self.assertTrue(lines[1].endswith(' T _bar_internal')) 204 | shutil.rmtree('build/hide_symbols') 205 | 206 | def test_copy_dlls(self): 207 | if os_name == 'windows': 208 | self.check_generate('copy_dlls', args='-DCOPY_DLLS=0') 209 | self.check_build('copy_dlls', args='--config Release') 210 | items = os.listdir('build/copy_dlls/test/Release') 211 | self.assertEqual(len(items), 1, items) 212 | self.assertTrue(items[0] == 'test.exe') 213 | shutil.rmtree('build/copy_dlls') 214 | 215 | self.check_generate('copy_dlls', args='-DCOPY_DLLS=1') 216 | self.check_build('copy_dlls', args='--config Release') 217 | items = os.listdir('build/copy_dlls/test/Release') 218 | self.assertEqual(len(items), 4) 219 | self.assertTrue(items[0] == 'bar.dll') 220 | self.assertTrue(items[1] == 'baz.dll') 221 | self.assertTrue(items[2] == 'foo.dll') 222 | self.assertTrue(items[3] == 'test.exe') 223 | shutil.rmtree('build/copy_dlls') 224 | 225 | def test_link_as_needed(self): 226 | if os_name == 'linux': 227 | self.check_generate('link_as_needed', args='-DLINK_AS_NEEDED=0') 228 | self.check_build('link_as_needed') 229 | cmd = 'ldd build/link_as_needed/libfoo_math.so' 230 | ret, out = check_output(cmd) 231 | self.assertEqual(0, ret, out) 232 | self.assertIn('libfoo.so =>', out) 233 | shutil.rmtree('build/link_as_needed') 234 | 235 | self.check_generate('link_as_needed', args='-DLINK_AS_NEEDED=1') 236 | self.check_build('link_as_needed') 237 | cmd = 'ldd build/link_as_needed/libfoo_math.so' 238 | ret, out = check_output(cmd) 239 | self.assertEqual(0, ret, out) 240 | self.assertTrue('libfoo.so =>' not in out) 241 | shutil.rmtree('build/link_as_needed') 242 | elif os_name == 'mac': 243 | self.check_generate('link_as_needed', args='-DLINK_AS_NEEDED=0') 244 | self.check_build('link_as_needed') 245 | cmd = 'otool -L build/link_as_needed/libfoo_math.dylib' 246 | ret, out = check_output(cmd) 247 | self.assertEqual(0, ret, out) 248 | self.assertIn('@rpath/libfoo.dylib', out) 249 | shutil.rmtree('build/link_as_needed') 250 | 251 | self.check_generate('link_as_needed', args='-DLINK_AS_NEEDED=1') 252 | self.check_build('link_as_needed') 253 | cmd = 'otool -L build/link_as_needed/libfoo_math.dylib' 254 | ret, out = check_output(cmd) 255 | self.assertEqual(0, ret, out) 256 | self.assertTrue('@rpath/libfoo.dylib' not in out) 257 | shutil.rmtree('build/link_as_needed') 258 | 259 | def test_unused_data_and_function(self): 260 | if os_name == 'mac': 261 | self.check_generate('unused_data_and_function', args='-DCMAKE_BUILD_TYPE=Release -DREMOVE_UNUSED_DATA_AND_FUNCTION=0') 262 | self.check_build('unused_data_and_function') 263 | cmd = 'objdump -t build/unused_data_and_function/test' 264 | ret, out = check_output(cmd) 265 | self.assertEqual(0, ret, out) 266 | out = out.replace('\r\n', '\n') 267 | lines = out.strip().split('\n') 268 | self.assertTrue(any(line.strip().endswith("g F __TEXT,__text _unused_function") for line in lines)) 269 | self.assertTrue(any(line.strip().endswith("g O __DATA,__data _unused_global_variable") for line in lines)) 270 | shutil.rmtree('build/unused_data_and_function') 271 | 272 | self.check_generate('unused_data_and_function', args='-DCMAKE_BUILD_TYPE=Release -DREMOVE_UNUSED_DATA_AND_FUNCTION=1') 273 | self.check_build('unused_data_and_function') 274 | cmd = 'objdump -t build/unused_data_and_function/test' 275 | ret, out = check_output(cmd) 276 | self.assertEqual(0, ret, out) 277 | out = out.replace('\r\n', '\n') 278 | lines = out.strip().split('\n') 279 | self.assertTrue(all(not line.strip().endswith("g F __TEXT,__text _unused_function") for line in lines)) 280 | self.assertTrue(all(not line.strip().endswith("g O __DATA,__data _unused_global_variable") for line in lines)) 281 | shutil.rmtree('build/unused_data_and_function') 282 | elif os_name == 'linux': 283 | self.check_generate('unused_data_and_function', args='-DCMAKE_BUILD_TYPE=Release -DREMOVE_UNUSED_DATA_AND_FUNCTION=0') 284 | self.check_build('unused_data_and_function') 285 | cmd = 'objdump -t build/unused_data_and_function/test' 286 | ret, out = check_output(cmd) 287 | self.assertEqual(0, ret, out) 288 | out = out.replace('\r\n', '\n') 289 | lines = out.strip().split('\n') 290 | self.assertTrue(any(line.strip().endswith(" unused_function") for line in lines)) 291 | self.assertTrue(any(line.strip().endswith(" unused_global_variable") for line in lines)) 292 | shutil.rmtree('build/unused_data_and_function') 293 | 294 | self.check_generate('unused_data_and_function', args='-DCMAKE_BUILD_TYPE=Release -DREMOVE_UNUSED_DATA_AND_FUNCTION=1') 295 | self.check_build('unused_data_and_function') 296 | cmd = 'objdump -t build/unused_data_and_function/test' 297 | ret, out = check_output(cmd) 298 | self.assertEqual(0, ret, out) 299 | out = out.replace('\r\n', '\n') 300 | lines = out.strip().split('\n') 301 | self.assertTrue(all(not line.strip().endswith(" unused_function") for line in lines)) 302 | self.assertTrue(all(not line.strip().endswith(" unused_global_variable") for line in lines)) 303 | shutil.rmtree('build/unused_data_and_function') 304 | 305 | if __name__ == "__main__": 306 | unittest.main() -------------------------------------------------------------------------------- /tests/artifacts_path/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_artifacts_path LANGUAGES C) 3 | include(../../rocbuild.cmake) 4 | add_library(foo_static STATIC ../src/foo.c) 5 | add_library(foo_shared SHARED ../src/foo.c) 6 | add_executable(hello ../src/hello.c) 7 | 8 | add_subdirectory(sub) -------------------------------------------------------------------------------- /tests/artifacts_path/sub/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(subfoo_static STATIC ../../src/foo.c) 2 | add_library(subfoo_shared SHARED ../../src/foo.c) 3 | add_executable(subhello ../../src/hello.c) -------------------------------------------------------------------------------- /tests/asan/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_asan) 3 | 4 | include(../../rocbuild.cmake) 5 | 6 | add_executable(basic-global-overflow basic-global-overflow.cpp) 7 | rocbuild_enable_asan(basic-global-overflow) 8 | 9 | add_library(matrix INTERFACE matrix.hpp) 10 | add_executable(test_matrix test_matrix.cpp) 11 | target_link_libraries(test_matrix PRIVATE matrix) 12 | rocbuild_enable_asan(matrix) 13 | 14 | set(OpenCV_DIR "C:/pkgs/opencv/4.10.0/x64/vc16/lib") 15 | find_package(OpenCV REQUIRED) 16 | add_executable(use_opencv use_opencv.cpp) 17 | target_link_libraries(use_opencv PRIVATE opencv_core) 18 | #rocbuild_copy_dlls(use_opencv) 19 | rocbuild_enable_asan(use_opencv) 20 | rocbuild_set_vs_debugger_environment(use_opencv) 21 | -------------------------------------------------------------------------------- /tests/asan/basic-global-overflow.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int x[100]; 3 | int main() { 4 | printf("Hello!\n"); 5 | x[100] = 5; // Boom! 6 | return 0; 7 | } -------------------------------------------------------------------------------- /tests/asan/matrix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class Matrix 4 | { 5 | public: 6 | Matrix(int rows, int cols) : rows(rows), cols(cols) 7 | { 8 | data = new int[rows * cols]; 9 | } 10 | 11 | ~Matrix() 12 | { 13 | delete[] data; 14 | } 15 | 16 | int& operator()(int i, int j) 17 | { 18 | return data[i * cols + j]; 19 | } 20 | 21 | int operator()(int i, int j) const 22 | { 23 | return data[i * cols + j]; 24 | } 25 | 26 | int getRows() const 27 | { 28 | return rows; 29 | } 30 | 31 | int getCols() const 32 | { 33 | return cols; 34 | } 35 | 36 | private: 37 | int rows; 38 | int cols; 39 | int* data; 40 | }; -------------------------------------------------------------------------------- /tests/asan/test_matrix.cpp: -------------------------------------------------------------------------------- 1 | #include "matrix.hpp" 2 | #include 3 | 4 | int main() 5 | { 6 | Matrix m(2, 2); 7 | m(0, 0) = 1; 8 | 9 | Matrix m2 = m; 10 | 11 | printf("bye\n"); 12 | 13 | return 0; 14 | } -------------------------------------------------------------------------------- /tests/asan/use_opencv.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | // Create a simple grayscale image (100x100) 6 | cv::Mat image = cv::Mat::zeros(100, 100, CV_8UC1); 7 | 8 | // Normal pixel access 9 | int x = 50, y = 50; 10 | image.data[y * image.cols + x] = 255; // Set the center pixel to white 11 | 12 | // Out-of-bounds access (directly manipulating the underlying data pointer) 13 | uchar* data = image.data; 14 | int total_pixels = image.rows * image.cols; 15 | 16 | // Construct an out-of-bounds access 17 | // This will not trigger any OpenCV checks but will cause undefined behavior 18 | uchar out_of_bounds_value = data[total_pixels + 10]; // Access beyond the image data 19 | std::cout << "Out of bounds value: " << (int)out_of_bounds_value << std::endl; 20 | 21 | return 0; 22 | } -------------------------------------------------------------------------------- /tests/copy_dlls/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_copy_dlls) 3 | 4 | include(../../rocbuild.cmake) 5 | 6 | add_library(foo SHARED ../src/foo.c) 7 | target_compile_definitions(foo PRIVATE FOO_EXPORTS) 8 | target_include_directories(foo PUBLIC ../src) 9 | set_target_properties(foo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/foo) 10 | 11 | add_library(bar SHARED ../src/bar.c ../src/bar_internal.c) 12 | target_compile_definitions(bar PRIVATE BAR_EXPORTS) 13 | target_include_directories(bar PUBLIC ../src) 14 | set_target_properties(bar PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bar) 15 | 16 | add_library(baz SHARED ../src/baz.c) 17 | target_compile_definitions(baz PRIVATE BAZ_EXPORTS) 18 | target_include_directories(baz PUBLIC ../src) 19 | set_target_properties(baz PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/baz) 20 | target_link_libraries(baz PRIVATE foo) 21 | 22 | add_executable(test test.c) 23 | target_link_libraries(test PRIVATE bar baz) 24 | set_target_properties(test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/test) 25 | 26 | if(COPY_DLLS) 27 | rocbuild_copy_dlls(test) 28 | endif() -------------------------------------------------------------------------------- /tests/copy_dlls/test.c: -------------------------------------------------------------------------------- 1 | #include "bar.h" 2 | #include "baz.h" 3 | 4 | int main() 5 | { 6 | return bar() + baz(); 7 | } -------------------------------------------------------------------------------- /tests/debug_postfix/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_postfix) 3 | 4 | include(../../rocbuild.cmake) 5 | 6 | add_library(foo STATIC ../src/foo.c) 7 | rocbuild_set_debug_postfix(foo) 8 | 9 | add_executable(hello ../src/hello.c) 10 | rocbuild_set_debug_postfix(hello) -------------------------------------------------------------------------------- /tests/hide_symbols/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_hide_symbols) 3 | 4 | include(../../rocbuild.cmake) 5 | 6 | add_library(bar SHARED 7 | ../src/bar.h 8 | ../src/bar.c 9 | ../src/bar_internal.h 10 | ../src/bar_internal.c 11 | ) 12 | target_include_directories(bar PRIVATE ../src) 13 | target_compile_definitions(bar PRIVATE BAR_EXPORTS) 14 | 15 | if(HIDDEN) 16 | rocbuild_hide_symbols(bar) 17 | endif() 18 | -------------------------------------------------------------------------------- /tests/link_as_needed/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(test_link_as_needed) 3 | 4 | include(../../rocbuild.cmake) 5 | 6 | # For test purpose, we explicitly enable `--no-as-needed` for GNU and Clang as the default behavior. 7 | if(CMAKE_C_COMPILER_ID MATCHES "^(GNU|Clang)$") 8 | add_link_options("LINKER:--no-as-needed") 9 | endif() 10 | 11 | add_library(foo_math SHARED 12 | foo_math.h 13 | foo_math.c 14 | ) 15 | target_include_directories(foo_math PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 16 | target_compile_definitions(foo_math PRIVATE FOO_MATH_EXPORTS) 17 | 18 | add_library(foo SHARED ../src/foo.c) 19 | target_include_directories(foo PRIVATE ../src) 20 | 21 | target_link_libraries(foo_math PRIVATE foo) 22 | 23 | if(LINK_AS_NEEDED) 24 | rocbuild_link_as_needed(foo_math) 25 | endif() 26 | -------------------------------------------------------------------------------- /tests/link_as_needed/foo_math.c: -------------------------------------------------------------------------------- 1 | #include "foo_math.h" 2 | #include 3 | 4 | static int compare(const void *a, const void *b) 5 | { 6 | int int_a = *(int *)a; 7 | int int_b = *(int *)b; 8 | 9 | if (int_a < int_b) return -1; 10 | else if (int_a > int_b) return 1; 11 | else return 0; 12 | } 13 | 14 | void abs_sort(int n, int* data) 15 | { 16 | for (int i = 0; i < n; i++) 17 | { 18 | data[i] = abs(i); 19 | } 20 | qsort(data, n, sizeof(int), compare); 21 | } 22 | -------------------------------------------------------------------------------- /tests/link_as_needed/foo_math.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef FOO_MATH_EXPORTS 4 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 5 | # define FOO_MATH_API __declspec(dllexport) 6 | # elif defined(__GNUC__) && __GNUC__ >= 4 7 | # define FOO_MATH_API __attribute__ ((visibility ("default"))) 8 | # endif 9 | #else 10 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 11 | # define FOO_MATH_API __declspec(dllimport) 12 | # else 13 | # define FOO_MATH_API 14 | # endif 15 | #endif 16 | 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | FOO_MATH_API 24 | void abs_sort(int n, int* data); 25 | 26 | #ifdef __cplusplus 27 | } 28 | #endif 29 | 30 | -------------------------------------------------------------------------------- /tests/lldb_string/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.20) 2 | project(hello) 3 | set(CMAKE_CXX_STANDARD 11) 4 | set(CMAKE_BUILD_TYPE Debug) 5 | find_package(OpenCV REQUIRED) 6 | include(../../debug_symbols.cmake) 7 | add_executable(testbed main.cpp) 8 | target_link_libraries(testbed ${OpenCV_LIBS}) 9 | 10 | -------------------------------------------------------------------------------- /tests/lldb_string/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void hello(const char* name) 6 | { 7 | if (name) 8 | { 9 | printf("hello %s\n", name); 10 | } 11 | else 12 | { 13 | printf("hello world\n"); 14 | } 15 | } 16 | 17 | class Point 18 | { 19 | public: 20 | int x, y; 21 | std::string name; 22 | 23 | public: 24 | Point(): x(0), y(0), name("unknown") {} 25 | Point(int _x, int _y, const std::string _name): x(_x), y(_y), name(_name) {} 26 | }; 27 | 28 | int main() 29 | { 30 | int a = 3; 31 | int b = 4; 32 | int c = a + b; 33 | printf("c = %d\n", c); 34 | int d = c + 6; 35 | printf("d = %d\n", d); 36 | 37 | printf("a = %d\n", a); 38 | a ++; 39 | printf("a = %d\n", a); 40 | 41 | hello(NULL); 42 | hello("ChrisZZ"); 43 | 44 | Point p1(a, b, "p1"); 45 | Point p2(c, d, "p2"); 46 | 47 | std::string name = "123"; 48 | 49 | 50 | #if __ANDROID__ 51 | std::string load_prefix = "/data/local/tmp"; 52 | #elif __linux__ 53 | std::string load_prefix = "/home/zz/data"; 54 | #elif _MSC_VER 55 | std::string load_prefix = "d:/data"; 56 | #else 57 | #pragma error 58 | #endif 59 | 60 | std::string filename = load_prefix + "/1920x1080.png"; 61 | cv::Mat src = cv::imread(filename); 62 | cv::Mat gray; 63 | cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); 64 | 65 | printf("done\n"); 66 | 67 | return 0; 68 | } -------------------------------------------------------------------------------- /tests/msvc_utf8_encoding/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.25) 2 | project(x) 3 | include(../../msvc_utf8_encoding.cmake) 4 | add_executable(test test.cpp) 5 | -------------------------------------------------------------------------------- /tests/msvc_utf8_encoding/test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | const std::string s = "你好"; 7 | printf("%s\n", s.c_str()); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /tests/src/bar.c: -------------------------------------------------------------------------------- 1 | #include "bar.h" 2 | #include "bar_internal.h" 3 | 4 | int bar() { return 1 + bar_internal(); } -------------------------------------------------------------------------------- /tests/src/bar.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef BAR_EXPORTS 4 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 5 | # define BAR_API __declspec(dllexport) 6 | # elif defined(__GNUC__) && __GNUC__ >= 4 7 | # define BAR_API __attribute__ ((visibility ("default"))) 8 | # endif 9 | #else 10 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 11 | # define BAR_API __declspec(dllimport) 12 | # else 13 | # define BAR_API 14 | # endif 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | BAR_API int bar(); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif -------------------------------------------------------------------------------- /tests/src/bar_internal.c: -------------------------------------------------------------------------------- 1 | #include "bar_internal.h" 2 | 3 | int bar_internal() 4 | { 5 | return 2; 6 | } -------------------------------------------------------------------------------- /tests/src/bar_internal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | int bar_internal(); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif -------------------------------------------------------------------------------- /tests/src/baz.c: -------------------------------------------------------------------------------- 1 | #include "baz.h" 2 | #include "foo.h" 3 | 4 | int baz() 5 | { 6 | return 2 + foo(); 7 | } -------------------------------------------------------------------------------- /tests/src/baz.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef BAZ_EXPORTS 4 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 5 | # define BAZ_API __declspec(dllexport) 6 | # elif defined(__GNUC__) && __GNUC__ >= 4 7 | # define BAZ_API __attribute__ ((visibility ("default"))) 8 | # endif 9 | #else 10 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 11 | # define BAZ_API __declspec(dllimport) 12 | # else 13 | # define BAZ_API 14 | # endif 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | BAZ_API int baz(); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif -------------------------------------------------------------------------------- /tests/src/foo.c: -------------------------------------------------------------------------------- 1 | #include "foo.h" 2 | 3 | int foo() { return 0; } -------------------------------------------------------------------------------- /tests/src/foo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef FOO_EXPORTS 4 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 5 | # define FOO_API __declspec(dllexport) 6 | # elif defined(__GNUC__) && __GNUC__ >= 4 7 | # define FOO_API __attribute__ ((visibility ("default"))) 8 | # endif 9 | #else 10 | # if defined(_MSC_VER) || defined(__CYGWIN__) || defined(__MINGW32__) 11 | # define FOO_API __declspec(dllimport) 12 | # else 13 | # define FOO_API 14 | # endif 15 | #endif 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | FOO_API int foo(); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif -------------------------------------------------------------------------------- /tests/src/hello.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | printf("hello\n"); 6 | } -------------------------------------------------------------------------------- /tests/unused_data_and_function/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(test_artifacts_path) 3 | include(../../rocbuild.cmake) 4 | 5 | add_executable(test test.c) 6 | if(REMOVE_UNUSED_DATA_AND_FUNCTION) 7 | rocbuild_remove_unused_data_and_function(test) 8 | endif() 9 | -------------------------------------------------------------------------------- /tests/unused_data_and_function/test.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Unused function (should be removed) 4 | void unused_function() { 5 | printf("This function is not used.\n"); 6 | } 7 | 8 | // Used function (should be kept) 9 | void used_function() { 10 | printf("This function is used.\n"); 11 | } 12 | 13 | // Unused global variable (should be removed) 14 | int unused_global_variable = 42; 15 | 16 | // Used global variable (should be kept) 17 | int used_global_variable = 100; 18 | 19 | int main() { 20 | void (*volatile func_ptr)() = used_function; 21 | func_ptr(); 22 | printf("Used global variable: %d\n", used_global_variable); 23 | return 0; 24 | } --------------------------------------------------------------------------------