first commit

This commit is contained in:
ChronosXYZ 2024-05-14 17:46:35 +03:00
commit 3413c94f8d
25 changed files with 1020 additions and 0 deletions

194
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,194 @@
name: Continuous Integration
on:
push:
branches:
- master
pull_request:
branches:
- master
jobs:
lint:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.8" }
- name: Install codespell
run: pip3 install codespell
- name: Lint
run: cmake -D FORMAT_COMMAND=clang-format-14 -P cmake/lint.cmake
- name: Spell check
if: always()
run: cmake -P cmake/spell.cmake
coverage:
needs: [lint]
runs-on: ubuntu-22.04
# To enable coverage, delete the last line from the conditional below and
# edit the "<name>" placeholder to your GitHub name.
# If you do not wish to use codecov, then simply delete this job from the
# workflow.
if: github.repository_owner == '<name>'
&& false
steps:
- uses: actions/checkout@v4
- name: Install LCov
run: sudo apt-get update -q
&& sudo apt-get install lcov -q -y
- name: Configure
run: cmake --preset=ci-coverage
- name: Build
run: cmake --build build/coverage -j 2
- name: Test
working-directory: build/coverage
run: ctest --output-on-failure --no-tests=error -j 2
- name: Process coverage info
run: cmake --build build/coverage -t coverage
- name: Submit to codecov.io
uses: codecov/codecov-action@v4
with:
file: build/coverage/coverage.info
token: ${{ secrets.CODECOV_TOKEN }}
sanitize:
needs: [lint]
runs-on: ubuntu-22.04
env: { CXX: clang++-14 }
steps:
- uses: actions/checkout@v4
- name: Configure
run: cmake --preset=ci-sanitize
- name: Build
run: cmake --build build/sanitize -j 2
- name: Test
working-directory: build/sanitize
env:
ASAN_OPTIONS: "strict_string_checks=1:\
detect_stack_use_after_return=1:\
check_initialization_order=1:\
strict_init_order=1:\
detect_leaks=1:\
halt_on_error=1"
UBSAN_OPTIONS: "print_stacktrace=1:\
halt_on_error=1"
run: ctest --output-on-failure --no-tests=error -j 2
test:
needs: [lint]
strategy:
matrix:
os: [macos-12, ubuntu-22.04, windows-2022]
type: [shared, static]
include:
- { type: shared, shared: YES }
- { type: static, shared: NO }
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install static analyzers
if: matrix.os == 'ubuntu-22.04'
run: >-
sudo apt-get install clang-tidy-14 cppcheck -y -q
sudo update-alternatives --install
/usr/bin/clang-tidy clang-tidy
/usr/bin/clang-tidy-14 140
- name: Setup MultiToolTask
if: matrix.os == 'windows-2022'
run: |
Add-Content "$env:GITHUB_ENV" 'UseMultiToolTask=true'
Add-Content "$env:GITHUB_ENV" 'EnforceProcessCountAcrossBuilds=true'
- name: Configure
shell: pwsh
run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])"
-D BUILD_SHARED_LIBS=${{ matrix.shared }}
- name: Setup PATH
if: matrix.os == 'windows-2022' && matrix.type == 'shared'
run: Add-Content "$env:GITHUB_PATH" "$(Get-Location)\build\Release"
- name: Build
run: cmake --build build --config Release -j 2
- name: Install
run: cmake --install build --config Release --prefix prefix
- name: Test
working-directory: build
run: ctest --output-on-failure --no-tests=error -C Release -j 2
docs:
# Deploy docs only when builds succeed
needs: [sanitize, test]
runs-on: ubuntu-22.04
# To enable, first you have to create an orphaned gh-pages branch:
#
# git switch --orphan gh-pages
# git commit --allow-empty -m "Initial commit"
# git push -u origin gh-pages
#
# Edit the <name> placeholder below to your GitHub name, so this action
# runs only in your repository and no one else's fork. After these, delete
# this comment and the last line in the conditional below.
# If you do not wish to use GitHub Pages for deploying documentation, then
# simply delete this job similarly to the coverage one.
if: github.ref == 'refs/heads/master'
&& github.event_name == 'push'
&& github.repository_owner == '<name>'
&& false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with: { python-version: "3.8" }
- name: Install m.css dependencies
run: pip3 install jinja2 Pygments
- name: Install Doxygen
run: sudo apt-get update -q
&& sudo apt-get install doxygen -q -y
- name: Build docs
run: cmake "-DPROJECT_SOURCE_DIR=$PWD" "-DPROJECT_BINARY_DIR=$PWD/build"
-P cmake/docs-ci.cmake
- name: Deploy docs
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: build/docs/html

13
.gitignore vendored Normal file
View File

@ -0,0 +1,13 @@
**/.DS_Store
.idea/
.vs/
.vscode/
build/
cmake-build-*/
prefix/
.clangd
CMakeLists.txt.user
CMakeUserPresets.json
compile_commands.json
env.bat
env.ps1

82
CMakeLists.txt Normal file
View File

@ -0,0 +1,82 @@
cmake_minimum_required(VERSION 3.14)
include(cmake/prelude.cmake)
project(
nix-gcc-multi-issue
VERSION 0.1.0
DESCRIPTION "Short description"
HOMEPAGE_URL "https://example.com/"
LANGUAGES CXX
)
include(cmake/project-is-top-level.cmake)
include(cmake/variables.cmake)
# ---- Declare library ----
# build as 32-bit library
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
add_library(
nix-gcc-multi-issue_nix-gcc-multi-issue
SHARED
source/nix-gcc-multi-issue.cpp
)
add_library(nix-gcc-multi-issue::nix-gcc-multi-issue ALIAS nix-gcc-multi-issue_nix-gcc-multi-issue)
include(GenerateExportHeader)
generate_export_header(
nix-gcc-multi-issue_nix-gcc-multi-issue
BASE_NAME nix-gcc-multi-issue
EXPORT_FILE_NAME export/nix-gcc-multi-issue/nix-gcc-multi-issue_export.hpp
CUSTOM_CONTENT_FROM_VARIABLE pragma_suppress_c4251
)
if(NOT BUILD_SHARED_LIBS)
target_compile_definitions(nix-gcc-multi-issue_nix-gcc-multi-issue PUBLIC NIX_GCC_MULTI_ISSUE_STATIC_DEFINE)
endif()
set_target_properties(
nix-gcc-multi-issue_nix-gcc-multi-issue PROPERTIES
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
VERSION "${PROJECT_VERSION}"
SOVERSION "${PROJECT_VERSION_MAJOR}"
EXPORT_NAME nix-gcc-multi-issue
OUTPUT_NAME nix-gcc-multi-issue
)
target_include_directories(
nix-gcc-multi-issue_nix-gcc-multi-issue ${warning_guard}
PUBLIC
"\$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>"
)
target_include_directories(
nix-gcc-multi-issue_nix-gcc-multi-issue SYSTEM
PUBLIC
"\$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/export>"
)
target_compile_features(nix-gcc-multi-issue_nix-gcc-multi-issue PUBLIC cxx_std_17)
# ---- Install rules ----
if(NOT CMAKE_SKIP_INSTALL_RULES)
include(cmake/install-rules.cmake)
endif()
# ---- Developer mode ----
if(NOT nix-gcc-multi-issue_DEVELOPER_MODE)
return()
elseif(NOT PROJECT_IS_TOP_LEVEL)
message(
AUTHOR_WARNING
"Developer mode is intended for developers of nix-gcc-multi-issue"
)
endif()
include(cmake/dev-mode.cmake)

19
README.md Normal file
View File

@ -0,0 +1,19 @@
# nix-gcc-multi-issue
This is the nix-gcc-multi-issue project.
# Building and installing
See the [BUILDING](BUILDING.md) document.
# Contributing
See the [CONTRIBUTING](CONTRIBUTING.md) document.
# Licensing
<!--
Please go to https://choosealicense.com/licenses/ and choose a license that
fits your needs. The recommended license for a project of this type is the
Boost Software License 1.0.
-->

15
build.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
[ -z $CONFIG ] && config=Release || config="$CONFIG"
if [ "$SKIP_CMAKE" != "true" ]; then
cmake \
-S . \
-B build \
-G Ninja \
-DCMAKE_BUILD_TYPE=$config
fi
cmake \
--build build \
--config $config \
--parallel $(nproc)

33
cmake/coverage.cmake Normal file
View File

@ -0,0 +1,33 @@
# ---- Variables ----
# We use variables separate from what CTest uses, because those have
# customization issues
set(
COVERAGE_TRACE_COMMAND
lcov -c -q
-o "${PROJECT_BINARY_DIR}/coverage.info"
-d "${PROJECT_BINARY_DIR}"
--include "${PROJECT_SOURCE_DIR}/*"
CACHE STRING
"; separated command to generate a trace for the 'coverage' target"
)
set(
COVERAGE_HTML_COMMAND
genhtml --legend -f -q
"${PROJECT_BINARY_DIR}/coverage.info"
-p "${PROJECT_SOURCE_DIR}"
-o "${PROJECT_BINARY_DIR}/coverage_html"
CACHE STRING
"; separated command to generate an HTML report for the 'coverage' target"
)
# ---- Coverage target ----
add_custom_target(
coverage
COMMAND ${COVERAGE_TRACE_COMMAND}
COMMAND ${COVERAGE_HTML_COMMAND}
COMMENT "Generating coverage report"
VERBATIM
)

21
cmake/dev-mode.cmake Normal file
View File

@ -0,0 +1,21 @@
include(cmake/folders.cmake)
include(CTest)
if(BUILD_TESTING)
add_subdirectory(test)
endif()
option(BUILD_MCSS_DOCS "Build documentation using Doxygen and m.css" OFF)
if(BUILD_MCSS_DOCS)
include(cmake/docs.cmake)
endif()
option(ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF)
if(ENABLE_COVERAGE)
include(cmake/coverage.cmake)
endif()
include(cmake/lint-targets.cmake)
include(cmake/spell-targets.cmake)
add_folders(Project)

112
cmake/docs-ci.cmake Normal file
View File

@ -0,0 +1,112 @@
cmake_minimum_required(VERSION 3.14)
foreach(var IN ITEMS PROJECT_BINARY_DIR PROJECT_SOURCE_DIR)
if(NOT DEFINED "${var}")
message(FATAL_ERROR "${var} must be defined")
endif()
endforeach()
set(bin "${PROJECT_BINARY_DIR}")
set(src "${PROJECT_SOURCE_DIR}")
# ---- Dependencies ----
set(mcss_SOURCE_DIR "${bin}/docs/.ci")
if(NOT IS_DIRECTORY "${mcss_SOURCE_DIR}")
file(MAKE_DIRECTORY "${mcss_SOURCE_DIR}")
file(
DOWNLOAD
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
"${mcss_SOURCE_DIR}/mcss.zip"
STATUS status
EXPECTED_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
)
if(NOT status MATCHES "^0;")
message(FATAL_ERROR "Download failed with ${status}")
endif()
execute_process(
COMMAND "${CMAKE_COMMAND}" -E tar xf mcss.zip
WORKING_DIRECTORY "${mcss_SOURCE_DIR}"
RESULT_VARIABLE result
)
if(NOT result EQUAL "0")
message(FATAL_ERROR "Extraction failed with ${result}")
endif()
file(REMOVE "${mcss_SOURCE_DIR}/mcss.zip")
endif()
find_program(Python3_EXECUTABLE NAMES python3 python)
if(NOT Python3_EXECUTABLE)
message(FATAL_ERROR "Python executable was not found")
endif()
# ---- Process project() call in CMakeLists.txt ----
file(READ "${src}/CMakeLists.txt" content)
string(FIND "${content}" "project(" index)
if(index EQUAL "-1")
message(FATAL_ERROR "Could not find \"project(\"")
endif()
string(SUBSTRING "${content}" "${index}" -1 content)
string(FIND "${content}" "\n)\n" index)
if(index EQUAL "-1")
message(FATAL_ERROR "Could not find \"\\n)\\n\"")
endif()
string(SUBSTRING "${content}" 0 "${index}" content)
file(WRITE "${bin}/docs-ci.project.cmake" "docs_${content}\n)\n")
macro(list_pop_front list out)
list(GET "${list}" 0 "${out}")
list(REMOVE_AT "${list}" 0)
endmacro()
function(docs_project name)
cmake_parse_arguments(PARSE_ARGV 1 "" "" "VERSION;DESCRIPTION;HOMEPAGE_URL" LANGUAGES)
set(PROJECT_NAME "${name}" PARENT_SCOPE)
if(DEFINED _VERSION)
set(PROJECT_VERSION "${_VERSION}" PARENT_SCOPE)
string(REGEX MATCH "^[0-9]+(\\.[0-9]+)*" versions "${_VERSION}")
string(REPLACE . ";" versions "${versions}")
set(suffixes MAJOR MINOR PATCH TWEAK)
while(NOT versions STREQUAL "" AND NOT suffixes STREQUAL "")
list_pop_front(versions version)
list_pop_front(suffixes suffix)
set("PROJECT_VERSION_${suffix}" "${version}" PARENT_SCOPE)
endwhile()
endif()
if(DEFINED _DESCRIPTION)
set(PROJECT_DESCRIPTION "${_DESCRIPTION}" PARENT_SCOPE)
endif()
if(DEFINED _HOMEPAGE_URL)
set(PROJECT_HOMEPAGE_URL "${_HOMEPAGE_URL}" PARENT_SCOPE)
endif()
endfunction()
include("${bin}/docs-ci.project.cmake")
# ---- Generate docs ----
if(NOT DEFINED DOXYGEN_OUTPUT_DIRECTORY)
set(DOXYGEN_OUTPUT_DIRECTORY "${bin}/docs")
endif()
set(out "${DOXYGEN_OUTPUT_DIRECTORY}")
foreach(file IN ITEMS Doxyfile conf.py)
configure_file("${src}/docs/${file}.in" "${bin}/docs/${file}" @ONLY)
endforeach()
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
set(config "${bin}/docs/conf.py")
file(REMOVE_RECURSE "${out}/html" "${out}/xml")
execute_process(
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
WORKING_DIRECTORY "${bin}/docs"
RESULT_VARIABLE result
)
if(NOT result EQUAL "0")
message(FATAL_ERROR "m.css returned with ${result}")
endif()

46
cmake/docs.cmake Normal file
View File

@ -0,0 +1,46 @@
# ---- Dependencies ----
set(extract_timestamps "")
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24")
set(extract_timestamps DOWNLOAD_EXTRACT_TIMESTAMP YES)
endif()
include(FetchContent)
FetchContent_Declare(
mcss URL
https://github.com/friendlyanon/m.css/releases/download/release-1/mcss.zip
URL_MD5 00cd2757ebafb9bcba7f5d399b3bec7f
SOURCE_DIR "${PROJECT_BINARY_DIR}/mcss"
UPDATE_DISCONNECTED YES
${extract_timestamps}
)
FetchContent_MakeAvailable(mcss)
find_package(Python3 3.6 REQUIRED)
# ---- Declare documentation target ----
set(
DOXYGEN_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/docs"
CACHE PATH "Path for the generated Doxygen documentation"
)
set(working_dir "${PROJECT_BINARY_DIR}/docs")
foreach(file IN ITEMS Doxyfile conf.py)
configure_file("docs/${file}.in" "${working_dir}/${file}" @ONLY)
endforeach()
set(mcss_script "${mcss_SOURCE_DIR}/documentation/doxygen.py")
set(config "${working_dir}/conf.py")
add_custom_target(
docs
COMMAND "${CMAKE_COMMAND}" -E remove_directory
"${DOXYGEN_OUTPUT_DIRECTORY}/html"
"${DOXYGEN_OUTPUT_DIRECTORY}/xml"
COMMAND "${Python3_EXECUTABLE}" "${mcss_script}" "${config}"
COMMENT "Building documentation using Doxygen and m.css"
WORKING_DIRECTORY "${working_dir}"
VERBATIM
)

21
cmake/folders.cmake Normal file
View File

@ -0,0 +1,21 @@
set_property(GLOBAL PROPERTY USE_FOLDERS YES)
# Call this function at the end of a directory scope to assign a folder to
# targets created in that directory. Utility targets will be assigned to the
# UtilityTargets folder, otherwise to the ${name}Targets folder. If a target
# already has a folder assigned, then that target will be skipped.
function(add_folders name)
get_property(targets DIRECTORY PROPERTY BUILDSYSTEM_TARGETS)
foreach(target IN LISTS targets)
get_property(folder TARGET "${target}" PROPERTY FOLDER)
if(DEFINED folder)
continue()
endif()
set(folder Utility)
get_property(type TARGET "${target}" PROPERTY TYPE)
if(NOT type STREQUAL "UTILITY")
set(folder "${name}")
endif()
set_property(TARGET "${target}" PROPERTY FOLDER "${folder}Targets")
endforeach()
endfunction()

View File

@ -0,0 +1 @@
include("${CMAKE_CURRENT_LIST_DIR}/nix-gcc-multi-issueTargets.cmake")

72
cmake/install-rules.cmake Normal file
View File

@ -0,0 +1,72 @@
if(PROJECT_IS_TOP_LEVEL)
set(
CMAKE_INSTALL_INCLUDEDIR "include/nix-gcc-multi-issue-${PROJECT_VERSION}"
CACHE STRING ""
)
set_property(CACHE CMAKE_INSTALL_INCLUDEDIR PROPERTY TYPE PATH)
endif()
include(CMakePackageConfigHelpers)
include(GNUInstallDirs)
# find_package(<package>) call for consumers to find this project
set(package nix-gcc-multi-issue)
install(
DIRECTORY
include/
"${PROJECT_BINARY_DIR}/export/"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT nix-gcc-multi-issue_Development
)
install(
TARGETS nix-gcc-multi-issue_nix-gcc-multi-issue
EXPORT nix-gcc-multi-issueTargets
RUNTIME #
COMPONENT nix-gcc-multi-issue_Runtime
LIBRARY #
COMPONENT nix-gcc-multi-issue_Runtime
NAMELINK_COMPONENT nix-gcc-multi-issue_Development
ARCHIVE #
COMPONENT nix-gcc-multi-issue_Development
INCLUDES #
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
)
write_basic_package_version_file(
"${package}ConfigVersion.cmake"
COMPATIBILITY SameMajorVersion
)
# Allow package maintainers to freely override the path for the configs
set(
nix-gcc-multi-issue_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/${package}"
CACHE STRING "CMake package config location relative to the install prefix"
)
set_property(CACHE nix-gcc-multi-issue_INSTALL_CMAKEDIR PROPERTY TYPE PATH)
mark_as_advanced(nix-gcc-multi-issue_INSTALL_CMAKEDIR)
install(
FILES cmake/install-config.cmake
DESTINATION "${nix-gcc-multi-issue_INSTALL_CMAKEDIR}"
RENAME "${package}Config.cmake"
COMPONENT nix-gcc-multi-issue_Development
)
install(
FILES "${PROJECT_BINARY_DIR}/${package}ConfigVersion.cmake"
DESTINATION "${nix-gcc-multi-issue_INSTALL_CMAKEDIR}"
COMPONENT nix-gcc-multi-issue_Development
)
install(
EXPORT nix-gcc-multi-issueTargets
NAMESPACE nix-gcc-multi-issue::
DESTINATION "${nix-gcc-multi-issue_INSTALL_CMAKEDIR}"
COMPONENT nix-gcc-multi-issue_Development
)
if(PROJECT_IS_TOP_LEVEL)
include(CPack)
endif()

33
cmake/lint-targets.cmake Normal file
View File

@ -0,0 +1,33 @@
set(
FORMAT_PATTERNS
source/*.cpp source/*.hpp
include/*.hpp
test/*.cpp test/*.hpp
CACHE STRING
"; separated patterns relative to the project source dir to format"
)
set(FORMAT_COMMAND clang-format CACHE STRING "Formatter to use")
add_custom_target(
format-check
COMMAND "${CMAKE_COMMAND}"
-D "FORMAT_COMMAND=${FORMAT_COMMAND}"
-D "PATTERNS=${FORMAT_PATTERNS}"
-P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
COMMENT "Linting the code"
VERBATIM
)
add_custom_target(
format-fix
COMMAND "${CMAKE_COMMAND}"
-D "FORMAT_COMMAND=${FORMAT_COMMAND}"
-D "PATTERNS=${FORMAT_PATTERNS}"
-D FIX=YES
-P "${PROJECT_SOURCE_DIR}/cmake/lint.cmake"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
COMMENT "Fixing the code"
VERBATIM
)

51
cmake/lint.cmake Normal file
View File

@ -0,0 +1,51 @@
cmake_minimum_required(VERSION 3.14)
macro(default name)
if(NOT DEFINED "${name}")
set("${name}" "${ARGN}")
endif()
endmacro()
default(FORMAT_COMMAND clang-format)
default(
PATTERNS
source/*.cpp source/*.hpp
include/*.hpp
test/*.cpp test/*.hpp
)
default(FIX NO)
set(flag --output-replacements-xml)
set(args OUTPUT_VARIABLE output)
if(FIX)
set(flag -i)
set(args "")
endif()
file(GLOB_RECURSE files ${PATTERNS})
set(badly_formatted "")
set(output "")
string(LENGTH "${CMAKE_SOURCE_DIR}/" path_prefix_length)
foreach(file IN LISTS files)
execute_process(
COMMAND "${FORMAT_COMMAND}" --style=file "${flag}" "${file}"
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE result
${args}
)
if(NOT result EQUAL "0")
message(FATAL_ERROR "'${file}': formatter returned with ${result}")
endif()
if(NOT FIX AND output MATCHES "\n<replacement offset")
string(SUBSTRING "${file}" "${path_prefix_length}" -1 relative_file)
list(APPEND badly_formatted "${relative_file}")
endif()
set(output "")
endforeach()
if(NOT badly_formatted STREQUAL "")
list(JOIN badly_formatted "\n" bad_list)
message("The following files are badly formatted:\n\n${bad_list}\n")
message(FATAL_ERROR "Run again with FIX=YES to fix these files.")
endif()

10
cmake/prelude.cmake Normal file
View File

@ -0,0 +1,10 @@
# ---- In-source guard ----
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(
FATAL_ERROR
"In-source builds are not supported. "
"Please read the BUILDING document before trying to build this project. "
"You may need to delete 'CMakeCache.txt' and 'CMakeFiles/' first."
)
endif()

View File

@ -0,0 +1,6 @@
# This variable is set by project() in CMake 3.21+
string(
COMPARE EQUAL
"${CMAKE_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}"
PROJECT_IS_TOP_LEVEL
)

22
cmake/spell-targets.cmake Normal file
View File

@ -0,0 +1,22 @@
set(SPELL_COMMAND codespell CACHE STRING "Spell checker to use")
add_custom_target(
spell-check
COMMAND "${CMAKE_COMMAND}"
-D "SPELL_COMMAND=${SPELL_COMMAND}"
-P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
COMMENT "Checking spelling"
VERBATIM
)
add_custom_target(
spell-fix
COMMAND "${CMAKE_COMMAND}"
-D "SPELL_COMMAND=${SPELL_COMMAND}"
-D FIX=YES
-P "${PROJECT_SOURCE_DIR}/cmake/spell.cmake"
WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}"
COMMENT "Fixing spelling errors"
VERBATIM
)

29
cmake/spell.cmake Normal file
View File

@ -0,0 +1,29 @@
cmake_minimum_required(VERSION 3.14)
macro(default name)
if(NOT DEFINED "${name}")
set("${name}" "${ARGN}")
endif()
endmacro()
default(SPELL_COMMAND codespell)
default(FIX NO)
set(flag "")
if(FIX)
set(flag -w)
endif()
execute_process(
COMMAND "${SPELL_COMMAND}" ${flag}
WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE result
)
if(result EQUAL "65")
message(FATAL_ERROR "Run again with FIX=YES to fix these errors.")
elseif(result EQUAL "64")
message(FATAL_ERROR "Spell checker printed the usage info. Bad arguments?")
elseif(NOT result EQUAL "0")
message(FATAL_ERROR "Spell checker returned with ${result}")
endif()

41
cmake/variables.cmake Normal file
View File

@ -0,0 +1,41 @@
# ---- Developer mode ----
# Developer mode enables targets and code paths in the CMake scripts that are
# only relevant for the developer(s) of nix-gcc-multi-issue
# Targets necessary to build the project must be provided unconditionally, so
# consumers can trivially build and package the project
if(PROJECT_IS_TOP_LEVEL)
option(nix-gcc-multi-issue_DEVELOPER_MODE "Enable developer mode" OFF)
option(BUILD_SHARED_LIBS "Build shared libs." OFF)
endif()
# ---- Suppress C4251 on Windows ----
# Please see include/nix-gcc-multi-issue/nix-gcc-multi-issue.hpp for more details
set(pragma_suppress_c4251 "
/* This needs to suppress only for MSVC */
#if defined(_MSC_VER) && !defined(__ICL)
# define NIX_GCC_MULTI_ISSUE_SUPPRESS_C4251 _Pragma(\"warning(suppress:4251)\")
#else
# define NIX_GCC_MULTI_ISSUE_SUPPRESS_C4251
#endif
")
# ---- Warning guard ----
# target_include_directories with the SYSTEM modifier will request the compiler
# to omit warnings from the provided paths, if the compiler supports that
# This is to provide a user experience similar to find_package when
# add_subdirectory or FetchContent is used to consume this project
set(warning_guard "")
if(NOT PROJECT_IS_TOP_LEVEL)
option(
nix-gcc-multi-issue_INCLUDES_WITH_SYSTEM
"Use SYSTEM modifier for nix-gcc-multi-issue's includes, disabling warnings"
ON
)
mark_as_advanced(nix-gcc-multi-issue_INCLUDES_WITH_SYSTEM)
if(nix-gcc-multi-issue_INCLUDES_WITH_SYSTEM)
set(warning_guard SYSTEM)
endif()
endif()

48
flake.lock generated Normal file
View File

@ -0,0 +1,48 @@
{
"nodes": {
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1714641030,
"narHash": "sha256-yzcRNDoyVP7+SCNX0wmuDju1NUCt8Dz9+lyUXEI0dbI=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "e5d10a24b66c3ea8f150e47dfdb0416ab7c3390e",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1715534503,
"narHash": "sha256-5ZSVkFadZbFP1THataCaSf0JH2cAH3S29hU9rrxTEqk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2057814051972fa1453ddfb0d98badbea9b83c06",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

31
flake.nix Normal file
View File

@ -0,0 +1,31 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts = {
url = "github:hercules-ci/flake-parts";
inputs.nixpkgs-lib.follows = "nixpkgs";
};
};
outputs =
inputs@{ flake-parts
, ...
}:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = [
"x86_64-linux"
];
perSystem = { pkgs, lib, system, self', ... }: {
devShells.default = pkgs.mkShell.override { stdenv = pkgs.multiStdenv; }
(with pkgs;
{
packages = [
pkg-config
cmake
ninja
];
});
};
};
}

View File

@ -0,0 +1,70 @@
#pragma once
#include <string>
#include "nix-gcc-multi-issue/nix-gcc-multi-issue_export.hpp"
/**
* A note about the MSVC warning C4251:
* This warning should be suppressed for private data members of the project's
* exported classes, because there are too many ways to work around it and all
* involve some kind of trade-off (increased code complexity requiring more
* developer time, writing boilerplate code, longer compile times), but those
* solutions are very situational and solve things in slightly different ways,
* depending on the requirements of the project.
* That is to say, there is no general solution.
*
* What can be done instead is understand where issues could arise where this
* warning is spotting a legitimate bug. I will give the general description of
* this warning's cause and break it down to make it trivial to understand.
*
* C4251 is emitted when an exported class has a non-static data member of a
* non-exported class type.
*
* The exported class in our case is the class below (exported_class), which
* has a non-static data member (m_name) of a non-exported class type
* (std::string).
*
* The rationale here is that the user of the exported class could attempt to
* access (directly, or via an inline member function) a static data member or
* a non-inline member function of the data member, resulting in a linker
* error.
* Inline member function above means member functions that are defined (not
* declared) in the class definition.
*
* Since this exported class never makes these non-exported types available to
* the user, we can safely ignore this warning. It's fine if there are
* non-exported class types as private member variables, because they are only
* accessed by the members of the exported class itself.
*
* The name() method below returns a pointer to the stored null-terminated
* string as a fundamental type (char const), so this is safe to use anywhere.
* The only downside is that you can have dangling pointers if the pointer
* outlives the class instance which stored the string.
*
* Shared libraries are not easy, they need some discipline to get right, but
* they also solve some other problems that make them worth the time invested.
*/
/**
* @brief Reports the name of the library
*
* Please see the note above for considerations when creating shared libraries.
*/
class NIX_GCC_MULTI_ISSUE_EXPORT exported_class
{
public:
/**
* @brief Initializes the name field to the name of the project
*/
exported_class();
/**
* @brief Returns a non-owning pointer to the string stored in this class
*/
auto name() const -> char const*;
private:
NIX_GCC_MULTI_ISSUE_SUPPRESS_C4251
std::string m_name;
};

View File

@ -0,0 +1,15 @@
#include <iostream>
#include <string>
#include "nix-gcc-multi-issue/nix-gcc-multi-issue.hpp"
exported_class::exported_class()
: m_name {"nix-gcc-multi-issue"}
{
std::cout << "Hello, World!" << std::endl;
}
auto exported_class::name() const -> char const*
{
return m_name.c_str();
}

25
test/CMakeLists.txt Normal file
View File

@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.14)
project(nix-gcc-multi-issueTests LANGUAGES CXX)
include(../cmake/project-is-top-level.cmake)
include(../cmake/folders.cmake)
# ---- Dependencies ----
if(PROJECT_IS_TOP_LEVEL)
find_package(nix-gcc-multi-issue REQUIRED)
enable_testing()
endif()
# ---- Tests ----
add_executable(nix-gcc-multi-issue_test source/nix-gcc-multi-issue_test.cpp)
target_link_libraries(nix-gcc-multi-issue_test PRIVATE nix-gcc-multi-issue::nix-gcc-multi-issue)
target_compile_features(nix-gcc-multi-issue_test PRIVATE cxx_std_17)
add_test(NAME nix-gcc-multi-issue_test COMMAND nix-gcc-multi-issue_test)
# ---- End-of-file commands ----
add_folders(Test)

View File

@ -0,0 +1,10 @@
#include <string>
#include "nix-gcc-multi-issue/nix-gcc-multi-issue.hpp"
auto main() -> int
{
auto const exported = exported_class {};
return std::string("nix-gcc-multi-issue") == exported.name() ? 0 : 1;
}