diff --git a/.clang-tidy b/.clang-tidy index 2d29f12..9a2afcc 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,41 +1,40 @@ Checks: ' -*, -bugprone-*, --bugprone-easily-swappable-parameters, --bugprone-exception-escape, --bugprone-move-forwarding-reference, --bugprone-narrowing-conversions, --bugprone-reserved-identifier, -misc-*, --misc-non-private-member-variables-in-classes, --misc-no-recursion, --misc-unconventional-assign-operator, --misc-unused-parameters, --misc-use-anonymous-namespace, -modernize-*, --modernize-avoid-c-arrays, --modernize-concat-nested-namespaces, --modernize-deprecated-headers, --modernize-use-nodiscard, --modernize-use-trailing-return-type, --modernize-use-using, +bugprone-argument-comment, +bugprone-move-forwarding-reference, +bugprone-string-constructor, +bugprone-use-after-move, +bugprone-lambda-function-name, +bugprone-unhandled-self-assignment, +misc-unused-using-decls, +misc-no-recursion, +modernize-deprecated-headers, +modernize-use-default-member-init, +modernize-use-emplace, +modernize-use-equals-default, +modernize-use-noexcept, +modernize-use-nullptr, +modernize-use-starts-ends-with, performance-*, -performance-avoid-endl, +-performance-enum-size, +-performance-inefficient-string-concatenation, +-performance-no-int-to-ptr, -performance-noexcept-move-constructor, -readability-*, --readability-braces-around-statements, --readability-convert-member-functions-to-static, --readability-else-after-return, --readability-function-cognitive-complexity, --readability-identifier-length, --readability-implicit-bool-conversion, --readability-inconsistent-declaration-parameter-name, --readability-magic-numbers, --readability-named-parameter, --readability-uppercase-literal-suffix, --readability-use-anyofallof, +-performance-unnecessary-value-param, +readability-const-return-type, +readability-redundant-declaration, +readability-redundant-string-init, +clang-analyzer-core.*, +-clang-analyzer-core.UndefinedBinaryOperatorResult, +clang-analyzer-optin.core.*, ' +HeaderFilterRegex: '.' +WarningsAsErrors: '*' CheckOptions: - - key: modernize-use-override.IgnoreDestructors - value: true -HeaderFilterRegex: 'example/calculator.h|example/init.h|example/printer.h|include/mp/proxy-io.h|include/mp/proxy-types.h|include/mp/proxy.h|include/mp/util.h|test/mp/test/foo-types.h|test/mp/test/foo.h' + - key: modernize-deprecated-headers.CheckHeaderFile + value: false + - key: performance-move-const-arg.CheckTriviallyCopyableMove + value: false + - key: bugprone-unhandled-self-assignment.WarnOnlyIfThisHasSuspiciousField + value: false diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a92e59a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,29 @@ +name: CI + +on: + push: + pull_request: + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + config: [default, llvm, gnu32] + + name: build • ${{ matrix.config }} + + steps: + - uses: actions/checkout@v4 + + - name: Install Nix + uses: cachix/install-nix-action@v31 # 2025-05-27, from https://github.com/cachix/install-nix-action/tags + with: + nix_path: nixpkgs=channel:nixos-25.05 # latest release + + - name: Run CI script + env: + CI_CONFIG: ci/configs/${{ matrix.config }}.sh + run: ci/scripts/run.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index f94086f..d29eb49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,16 +15,35 @@ include("cmake/compat_find.cmake") find_package(CapnProto REQUIRED) find_package(Threads REQUIRED) -option(Libmultiprocess_ENABLE_CLANG_TIDY "Run clang-tidy with the compiler." OFF) -if(Libmultiprocess_ENABLE_CLANG_TIDY) +set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.") + +option(MP_ENABLE_CLANG_TIDY "Run clang-tidy with the compiler." OFF) +if(MP_ENABLE_CLANG_TIDY) find_program(CLANG_TIDY_EXECUTABLE NAMES clang-tidy) if(NOT CLANG_TIDY_EXECUTABLE) - message(FATAL_ERROR "Libmultiprocess_ENABLE_CLANG_TIDY is ON but clang-tidy is not found.") + message(FATAL_ERROR "MP_ENABLE_CLANG_TIDY is ON but clang-tidy is not found.") endif() set(CMAKE_CXX_CLANG_TIDY "${CLANG_TIDY_EXECUTABLE}") + + # Workaround for nix from https://gitlab.kitware.com/cmake/cmake/-/issues/20912#note_793338 + # Nix injects header paths via $NIX_CFLAGS_COMPILE; CMake tags these as + # CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES and omits them from the compile + # database, so clang-tidy, which ignores $NIX_CFLAGS_COMPILE, can't find capnp + # headers. Setting them as standard passes them to clang-tidy. + set(CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}) endif() -set(MPGEN_EXECUTABLE "" CACHE FILEPATH "If specified, should be full path to an external mpgen binary to use rather than the one built internally.") +option(MP_ENABLE_IWYU "Run include-what-you-use with the compiler." OFF) +if(MP_ENABLE_IWYU) + find_program(IWYU_EXECUTABLE NAMES include-what-you-use iwyu) + if(NOT IWYU_EXECUTABLE) + message(FATAL_ERROR "MP_ENABLE_IWYU is ON but include-what-you-use was not found.") + endif() + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE "${IWYU_EXECUTABLE};-Xiwyu;--error") + if(DEFINED ENV{IWYU_MAPPING_FILE}) + list(APPEND CMAKE_CXX_INCLUDE_WHAT_YOU_USE "-Xiwyu" "--mapping_file=$ENV{IWYU_MAPPING_FILE}") + endif() +endif() include("cmake/compat_config.cmake") include("cmake/pthread_checks.cmake") @@ -51,6 +70,7 @@ configure_file(include/mp/config.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/mp/co # Generated C++ Capn'Proto schema files capnp_generate_cpp(MP_PROXY_SRCS MP_PROXY_HDRS include/mp/proxy.capnp) +set_source_files_properties("${MP_PROXY_SRCS}" PROPERTIES SKIP_LINTING TRUE) # Ignored before cmake 3.27 # util library add_library(mputil OBJECT src/mp/util.cpp) diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 0000000..9559912 --- /dev/null +++ b/ci/README.md @@ -0,0 +1,24 @@ +### CI quick-reference + +All CI is just bash and nix. + +* **Workflow**: + - `.github/workflows/ci.yml` – lists the jobs (`default`, `llvm`, …). +* **Scripts**: + - `ci/scripts/run.sh` – spins up the Nix shell then calls… + - `ci/scripts/ci.sh` – …to configure, build, and test. +* **Configuration**: + - `ci/configs/*.sh` – defines flags for each job. + - `shell.nix` – defines build environment (compilers, tools, libraries). +* **Build directories**: + - `build-*/` – separate build directories (like `build-default`, `build-llvm`) will be created for each job. + +To run jobs locally: + +```bash +CI_CONFIG=ci/configs/default.sh ci/scripts/run.sh +CI_CONFIG=ci/configs/llvm.sh ci/scripts/run.sh +CI_CONFIG=ci/configs/gnu32.sh ci/scripts/run.sh +``` + +By default CI jobs will reuse their build directories. `CI_CLEAN=1` can be specified to delete them before running instead. diff --git a/ci/configs/default.sh b/ci/configs/default.sh new file mode 100644 index 0000000..5623122 --- /dev/null +++ b/ci/configs/default.sh @@ -0,0 +1,5 @@ +CI_DESC="CI job using default libraries and tools, and running IWYU" +CI_DIR=build-default +export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter" +CMAKE_ARGS=(-DMP_ENABLE_IWYU=ON) +BUILD_ARGS=(-k) diff --git a/ci/configs/gnu32.sh b/ci/configs/gnu32.sh new file mode 100644 index 0000000..961821c --- /dev/null +++ b/ci/configs/gnu32.sh @@ -0,0 +1,9 @@ +CI_DESC="CI job cross-compiling to 32-bit" +CI_DIR=build-gnu32 +NIX_ARGS=( + --arg minimal true + --arg crossPkgs 'import { crossSystem = { config = "i686-unknown-linux-gnu"; }; }' +) +export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-unused-parameter" +CMAKE_ARGS=(-G Ninja) +BUILD_ARGS=(-k 0) diff --git a/ci/configs/llvm.sh b/ci/configs/llvm.sh new file mode 100644 index 0000000..afa957e --- /dev/null +++ b/ci/configs/llvm.sh @@ -0,0 +1,11 @@ +CI_DESC="CI job using LLVM-based libraries and tools (clang, libc++, clang-tidy, iwyu) and testing Ninja" +CI_DIR=build-llvm +NIX_ARGS=(--arg enableLibcxx true) +export CXX=clang++ +export CXXFLAGS="-Werror -Wall -Wextra -Wpedantic -Wthread-safety-analysis -Wno-unused-parameter" +CMAKE_ARGS=( + -G Ninja + -DMP_ENABLE_CLANG_TIDY=ON + -DMP_ENABLE_IWYU=ON +) +BUILD_ARGS=(-k 0) diff --git a/ci/scripts/ci.sh b/ci/scripts/ci.sh new file mode 100755 index 0000000..d636af2 --- /dev/null +++ b/ci/scripts/ci.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail -o xtrace + +[ "${CI_CONFIG+x}" ] && source "$CI_CONFIG" + +: "${CI_DIR:=build}" + +[ -n "${CI_CLEAN-}" ] && rm -rf "${CI_DIR}" + +cmake -B "$CI_DIR" "${CMAKE_ARGS[@]+"${CMAKE_ARGS[@]}"}" +cmake --build "$CI_DIR" -t all tests mpexamples -- "${BUILD_ARGS[@]+"${BUILD_ARGS[@]}"}" +ctest --test-dir "$CI_DIR" --output-on-failure diff --git a/ci/scripts/run.sh b/ci/scripts/run.sh new file mode 100755 index 0000000..5f5e30d --- /dev/null +++ b/ci/scripts/run.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +set -o errexit -o nounset -o pipefail -o xtrace + +[ "${CI_CONFIG+x}" ] && source "$CI_CONFIG" + +nix-shell --pure --keep CI_CONFIG --keep CI_CLEAN "${NIX_ARGS[@]+"${NIX_ARGS[@]}"}" --run ci/scripts/ci.sh shell.nix diff --git a/cmake/TargetCapnpSources.cmake b/cmake/TargetCapnpSources.cmake index cf7d20f..347ef4a 100644 --- a/cmake/TargetCapnpSources.cmake +++ b/cmake/TargetCapnpSources.cmake @@ -81,6 +81,8 @@ function(target_capnp_sources target include_prefix) DEPENDS ${capnp_file} VERBATIM ) + # Skip linting for capnp-generated files but keep it for mpgen-generated ones + set_source_files_properties(${capnp_file}.c++ PROPERTIES SKIP_LINTING TRUE) # Ignored before cmake 3.27 target_sources(${target} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${capnp_file}.c++ ${CMAKE_CURRENT_BINARY_DIR}/${capnp_file}.proxy-client.c++ diff --git a/example/calculator.cpp b/example/calculator.cpp index e94be4b..016a048 100644 --- a/example/calculator.cpp +++ b/example/calculator.cpp @@ -3,17 +3,21 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include +#include +#include // NOLINT(misc-include-cleaner) // IWYU pragma: keep + #include +#include #include -#include -#include // NOLINT(misc-include-cleaner) -#include #include +#include +#include +#include #include #include -#include #include #include +#include #include class CalculatorImpl : public Calculator diff --git a/example/example.cpp b/example/example.cpp index ce1a9ba..5088f79 100644 --- a/example/example.cpp +++ b/example/example.cpp @@ -2,12 +2,17 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include +#include + +#include // IWYU pragma: keep #include #include #include -#include -#include #include +#include +#include +#include #include #include #include diff --git a/example/init.capnp b/example/init.capnp index 03c8899..01897f1 100644 --- a/example/init.capnp +++ b/example/init.capnp @@ -12,8 +12,7 @@ using Printer = import "printer.capnp"; $Proxy.include("calculator.h"); $Proxy.include("init.h"); $Proxy.include("printer.h"); -$Proxy.includeTypes("calculator.capnp.proxy-types.h"); -$Proxy.includeTypes("printer.capnp.proxy-types.h"); +$Proxy.includeTypes("types.h"); interface InitInterface $Proxy.wrap("Init") { construct @0 (threadMap: Proxy.ThreadMap) -> (threadMap :Proxy.ThreadMap); diff --git a/example/printer.cpp b/example/printer.cpp index 931eab4..eb38401 100644 --- a/example/printer.cpp +++ b/example/printer.cpp @@ -2,17 +2,23 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include + +#include +#include // NOLINT(misc-include-cleaner) // IWYU pragma: keep + #include +#include #include -#include -#include // NOLINT(misc-include-cleaner) -#include #include +#include +#include +#include #include #include -#include #include #include +#include class PrinterImpl : public Printer { diff --git a/example/types.h b/example/types.h index 6b6b579..c926a00 100644 --- a/example/types.h +++ b/example/types.h @@ -5,10 +5,19 @@ #ifndef EXAMPLE_TYPES_H #define EXAMPLE_TYPES_H +#include +#include + +// IWYU pragma: begin_exports #include #include #include #include #include +// IWYU pragma: end_exports + +struct InitInterface; // IWYU pragma: export +struct CalculatorInterface; // IWYU pragma: export +struct PrinterInterface; // IWYU pragma: export #endif // EXAMPLE_TYPES_H diff --git a/include/mp/proxy-io.h b/include/mp/proxy-io.h index 9f3eed6..3ed7bad 100644 --- a/include/mp/proxy-io.h +++ b/include/mp/proxy-io.h @@ -13,6 +13,7 @@ #include #include +#include #include #include #include @@ -20,6 +21,7 @@ #include #include #include +#include namespace mp { struct ThreadContext; diff --git a/include/mp/proxy-types.h b/include/mp/proxy-types.h index c2f0986..597bdfd 100644 --- a/include/mp/proxy-types.h +++ b/include/mp/proxy-types.h @@ -92,9 +92,9 @@ struct StructField template struct ReadDestEmplace { - ReadDestEmplace(TypeList, EmplaceFn&& emplace_fn) : m_emplace_fn(emplace_fn) {} + ReadDestEmplace(TypeList, EmplaceFn emplace_fn) : m_emplace_fn(std::move(emplace_fn)) {} - //! Simple case. If ReadField impementation calls this construct() method + //! Simple case. If ReadField implementation calls this construct() method //! with constructor arguments, just pass them on to the emplace function. template decltype(auto) construct(Args&&... args) @@ -123,7 +123,7 @@ struct ReadDestEmplace return temp; } } - EmplaceFn& m_emplace_fn; + EmplaceFn m_emplace_fn; }; //! Helper function to create a ReadDestEmplace object that constructs a @@ -131,7 +131,7 @@ struct ReadDestEmplace template auto ReadDestTemp() { - return ReadDestEmplace{TypeList(), [&](auto&&... args) -> decltype(auto) { + return ReadDestEmplace{TypeList(), [](auto&&... args) -> decltype(auto) { return LocalType{std::forward(args)...}; }}; } @@ -191,7 +191,7 @@ void ThrowField(TypeList, InvokeContext& invoke_context, Input&& } template -bool CustomHasValue(InvokeContext& invoke_context, Values&&... value) +bool CustomHasValue(InvokeContext& invoke_context, const Values&... value) { return true; } @@ -199,7 +199,7 @@ bool CustomHasValue(InvokeContext& invoke_context, Values&&... value) template void BuildField(TypeList, Context& context, Output&& output, Values&&... values) { - if (CustomHasValue(context, std::forward(values)...)) { + if (CustomHasValue(context, values...)) { CustomBuildField(TypeList(), Priority<3>(), context, std::forward(values)..., std::forward(output)); } @@ -274,7 +274,7 @@ void MaybeReadField(std::false_type, Args&&...) } template -void MaybeSetWant(TypeList, Priority<1>, Value&& value, Output&& output) +void MaybeSetWant(TypeList, Priority<1>, const Value& value, Output&& output) { if (value) { output.setWant(); @@ -282,7 +282,7 @@ void MaybeSetWant(TypeList, Priority<1>, Value&& value, Output&& out } template -void MaybeSetWant(LocalTypes, Priority<0>, Args&&...) +void MaybeSetWant(LocalTypes, Priority<0>, const Args&...) { } @@ -326,18 +326,18 @@ template struct IterateFieldsHelper { template - void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args) + void handleChain(Arg1& arg1, Arg2& arg2, ParamList, NextFn&& next_fn, NextFnArgs&&... next_fn_args) { using S = Split; - handleChain(std::forward(arg1), std::forward(arg2), typename S::First()); - next_fn.handleChain(std::forward(arg1), std::forward(arg2), typename S::Second(), + handleChain(arg1, arg2, typename S::First()); + next_fn.handleChain(arg1, arg2, typename S::Second(), std::forward(next_fn_args)...); } template - void handleChain(Arg1&& arg1, Arg2&& arg2, ParamList) + void handleChain(Arg1& arg1, Arg2& arg2, ParamList) { - static_cast(this)->handleField(std::forward(arg1), std::forward(arg2), ParamList()); + static_cast(this)->handleField(arg1, arg2, ParamList()); } private: IterateFieldsHelper() = default; @@ -393,10 +393,10 @@ struct ClientParam void handleField(ClientInvokeContext& invoke_context, Params& params, ParamList) { auto const fun = [&](Values&&... values) { + MaybeSetWant( + ParamList(), Priority<1>(), values..., Make(params)); MaybeBuildField(std::integral_constant(), ParamList(), invoke_context, Make(params), std::forward(values)...); - MaybeSetWant( - ParamList(), Priority<1>(), std::forward(values)..., Make(params)); }; // Note: The m_values tuple just consists of lvalue and rvalue diff --git a/include/mp/proxy.h b/include/mp/proxy.h index 94c6582..fff511f 100644 --- a/include/mp/proxy.h +++ b/include/mp/proxy.h @@ -7,35 +7,31 @@ #include -#include #include #include #include +#include #include #include #include #include +#include // IWYU pragma: keep namespace mp { class Connection; class EventLoop; //! Mapping from capnp interface type to proxy client implementation (specializations are generated by //! proxy-codegen.cpp). -template -struct ProxyClient; +template struct ProxyClient; // IWYU pragma: export //! Mapping from capnp interface type to proxy server implementation (specializations are generated by //! proxy-codegen.cpp). -template -struct ProxyServer; +template struct ProxyServer; // IWYU pragma: export //! Mapping from capnp method params type to method traits (specializations are generated by proxy-codegen.cpp). -template -struct ProxyMethod; +template struct ProxyMethod; // IWYU pragma: export //! Mapping from capnp struct type to struct traits (specializations are generated by proxy-codegen.cpp). -template -struct ProxyStruct; +template struct ProxyStruct; // IWYU pragma: export //! Mapping from local c++ type to capnp type and traits (specializations are generated by proxy-codegen.cpp). -template -struct ProxyType; +template struct ProxyType; // IWYU pragma: export using CleanupList = std::list>; using CleanupIt = typename CleanupList::iterator; diff --git a/include/mp/type-number.h b/include/mp/type-number.h index 4d172a0..5c997f5 100644 --- a/include/mp/type-number.h +++ b/include/mp/type-number.h @@ -50,8 +50,14 @@ decltype(auto) CustomReadField(TypeList, InvokeContext& invoke_context, Input&& input, ReadDest&& read_dest, - typename std::enable_if::value>::type* enable = 0) + typename std::enable_if::value>::type* enable = nullptr) { + // Disable clang-tidy out-of-range enum value check which triggers when + // using an enum type that does not have a 0 value. The check correctly + // triggers when it detects that Cap'n Proto returns 0 when reading an + // integer field that is unset. But the warning is spurious because the + // corresponding BuildField call should never leave the field unset. + // NOLINTNEXTLINE(clang-analyzer-optin.core.EnumCastOutOfRange) return read_dest.construct(static_cast(input.get())); } diff --git a/include/mp/util.h b/include/mp/util.h index 22e8188..d9f3ca3 100644 --- a/include/mp/util.h +++ b/include/mp/util.h @@ -8,14 +8,10 @@ #include #include #include +#include #include -#include -#include -#include #include -#include #include -#include #include #include #include @@ -174,7 +170,7 @@ class MP_CAPABILITY("mutex") Mutex { class MP_SCOPED_CAPABILITY Lock { public: explicit Lock(Mutex& m) MP_ACQUIRE(m) : m_lock(m.m_mutex) {} - ~Lock() MP_RELEASE() {} + ~Lock() MP_RELEASE() = default; void unlock() MP_RELEASE() { m_lock.unlock(); } void lock() MP_ACQUIRE() { m_lock.lock(); } void assert_locked(Mutex& mutex) MP_ASSERT_CAPABILITY() MP_ASSERT_CAPABILITY(mutex) diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..eacfdc2 --- /dev/null +++ b/shell.nix @@ -0,0 +1,28 @@ +{ pkgs ? import {} +, crossPkgs ? import {} +, enableLibcxx ? false # Whether to use libc++ toolchain and libraries instead of libstdc++ +, minimal ? false # Whether to create minimal shell without extra tools (faster when cross compiling) +}: + +let + lib = pkgs.lib; + llvm = crossPkgs.llvmPackages_20; + capnproto = crossPkgs.capnproto.override (lib.optionalAttrs enableLibcxx { clangStdenv = llvm.libcxxStdenv; }); + clang = if enableLibcxx then llvm.libcxxClang else llvm.clang; + clang-tools = llvm.clang-tools.override { inherit enableLibcxx; }; +in crossPkgs.mkShell { + buildInputs = [ + capnproto + ]; + nativeBuildInputs = with pkgs; [ + cmake + include-what-you-use + ninja + ] ++ lib.optionals (!minimal) [ + clang + clang-tools + ]; + + # Tell IWYU where its libc++ mapping lives + IWYU_MAPPING_FILE = if enableLibcxx then "${llvm.libcxx.dev}/include/c++/v1/libcxx.imp" else null; +} diff --git a/src/mp/gen.cpp b/src/mp/gen.cpp index 22001eb..21a4d93 100644 --- a/src/mp/gen.cpp +++ b/src/mp/gen.cpp @@ -6,13 +6,15 @@ #include #include +#include #include +#include #include #include #include -#include #include #include +#include #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #define PROXY_BIN "mpgen" @@ -76,7 +79,7 @@ static bool GetAnnotationInt32(const Reader& reader, uint64_t id, int32_t* resul return false; } -static void ForEachMethod(const capnp::InterfaceSchema& interface, const std::function& callback) +static void ForEachMethod(const capnp::InterfaceSchema& interface, const std::function& callback) // NOLINT(misc-no-recursion) { for (const auto super : interface.getSuperclasses()) { ForEachMethod(super, callback); @@ -198,19 +201,45 @@ static void Generate(kj::StringPtr src_prefix, std::ofstream cpp_server(output_path + ".proxy-server.c++"); cpp_server << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + cpp_server << "// IWYU pragma: no_include \n"; + cpp_server << "// IWYU pragma: no_include \n"; + cpp_server << "// IWYU pragma: begin_keep\n"; + cpp_server << "#include <" << include_path << ".proxy.h>\n"; cpp_server << "#include <" << include_path << ".proxy-types.h>\n"; - cpp_server << "#include <" << PROXY_TYPES << ">\n\n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include \n"; + cpp_server << "#include <" << PROXY_TYPES << ">\n"; + cpp_server << "// IWYU pragma: end_keep\n\n"; cpp_server << "namespace mp {\n"; std::ofstream cpp_client(output_path + ".proxy-client.c++"); cpp_client << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; + cpp_client << "// IWYU pragma: no_include \n"; + cpp_client << "// IWYU pragma: no_include \n"; + cpp_client << "// IWYU pragma: begin_keep\n"; + cpp_client << "#include <" << include_path << ".h>\n"; + cpp_client << "#include <" << include_path << ".proxy.h>\n"; cpp_client << "#include <" << include_path << ".proxy-types.h>\n"; - cpp_client << "#include <" << PROXY_TYPES << ">\n\n"; + cpp_client << "#include \n"; + cpp_client << "#include \n"; + cpp_client << "#include \n"; + cpp_client << "#include \n"; + cpp_client << "#include \n"; + cpp_client << "#include <" << PROXY_TYPES << ">\n"; + cpp_client << "// IWYU pragma: end_keep\n\n"; cpp_client << "namespace mp {\n"; std::ofstream cpp_types(output_path + ".proxy-types.c++"); cpp_types << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; - cpp_types << "#include <" << include_path << ".proxy-types.h>\n"; + cpp_types << "// IWYU pragma: no_include \"mp/proxy.h\"\n"; + cpp_types << "// IWYU pragma: no_include \"mp/proxy-io.h\"\n"; + cpp_types << "#include <" << include_path << ".proxy.h>\n"; + cpp_types << "#include <" << include_path << ".proxy-types.h> // IWYU pragma: keep\n"; cpp_types << "#include <" << PROXY_TYPES << ">\n\n"; cpp_types << "namespace mp {\n"; @@ -226,10 +255,12 @@ static void Generate(kj::StringPtr src_prefix, inl << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; inl << "#ifndef " << guard << "_PROXY_TYPES_H\n"; inl << "#define " << guard << "_PROXY_TYPES_H\n\n"; - inl << "#include <" << include_path << ".proxy.h>\n"; + inl << "// IWYU pragma: no_include \"mp/proxy.h\"\n"; + inl << "#include // IWYU pragma: keep\n"; + inl << "#include <" << include_path << ".proxy.h> // IWYU pragma: keep\n"; for (const auto annotation : file_schema.getProto().getAnnotations()) { if (annotation.getId() == INCLUDE_TYPES_ANNOTATION_ID) { - inl << "#include <" << annotation.getValue().getText() << ">\n"; + inl << "#include \"" << annotation.getValue().getText() << "\" // IWYU pragma: export\n"; } } inl << "namespace mp {\n"; @@ -238,10 +269,10 @@ static void Generate(kj::StringPtr src_prefix, h << "// Generated by " PROXY_BIN " from " << src_file << "\n\n"; h << "#ifndef " << guard << "_PROXY_H\n"; h << "#define " << guard << "_PROXY_H\n\n"; - h << "#include <" << include_path << ".h>\n"; + h << "#include <" << include_path << ".h> // IWYU pragma: keep\n"; for (const auto annotation : file_schema.getProto().getAnnotations()) { if (annotation.getId() == INCLUDE_ANNOTATION_ID) { - h << "#include <" << annotation.getValue().getText() << ">\n"; + h << "#include \"" << annotation.getValue().getText() << "\" // IWYU pragma: export\n"; } } h << "#include <" << PROXY_DECL << ">\n\n"; diff --git a/src/mp/proxy.cpp b/src/mp/proxy.cpp index 0f5e566..579f799 100644 --- a/src/mp/proxy.cpp +++ b/src/mp/proxy.cpp @@ -10,24 +10,23 @@ #include #include -#include #include -#include #include +#include #include #include #include -#include #include +#include +#include #include #include -#include #include #include #include #include #include -#include +#include #include #include #include @@ -38,9 +37,6 @@ namespace mp { -template -struct ProxyServer; - thread_local ThreadContext g_thread_context; void LoggingErrorHandler::taskFailed(kj::Exception&& exception) diff --git a/src/mp/util.cpp b/src/mp/util.cpp index cbe8b9f..a948539 100644 --- a/src/mp/util.cpp +++ b/src/mp/util.cpp @@ -5,12 +5,12 @@ #include #include -#include +#include +#include #include #include #include #include -#include #include #include #include diff --git a/test/mp/test/foo-types.h b/test/mp/test/foo-types.h index bb7f304..e70bc4c 100644 --- a/test/mp/test/foo-types.h +++ b/test/mp/test/foo-types.h @@ -5,7 +5,13 @@ #ifndef MP_TEST_FOO_TYPES_H #define MP_TEST_FOO_TYPES_H +#include #include + +// IWYU pragma: begin_exports +#include +#include +#include #include #include #include @@ -18,9 +24,18 @@ #include #include #include +#include +#include +// IWYU pragma: end_exports namespace mp { namespace test { +namespace messages { +struct ExtendedCallback; // IWYU pragma: export +struct FooCallback; // IWYU pragma: export +struct FooFn; // IWYU pragma: export +struct FooInterface; // IWYU pragma: export +} // namespace messages template void CustomBuildField(TypeList, Priority<1>, InvokeContext& invoke_context, const FooCustom& value, Output&& output) diff --git a/test/mp/test/test.cpp b/test/mp/test/test.cpp index 37201a9..fa5a6f4 100644 --- a/test/mp/test/test.cpp +++ b/test/mp/test/test.cpp @@ -2,23 +2,32 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#include #include #include -#include #include -#include -#include +#include +#include #include +#include #include -#include +#include +#include #include +#include #include #include +#include +#include +#include +#include +#include +#include #include +#include #include #include +#include namespace mp { namespace test {