Skip to content

Commit

Permalink
ci: Include what you use (#2155)
Browse files Browse the repository at this point in the history
In this PR I set up a basic workflow to run [IWYU](https://github.com/include-what-you-use/include-what-you-use) and a filtering mechanism for its output.

My hope is that it could lead to accelerated build times and cleaner include flow.
  • Loading branch information
andiwand committed Jun 3, 2023
1 parent f81b812 commit 2563d3b
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 0 deletions.
70 changes: 70 additions & 0 deletions .github/workflows/iwyu.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: IWYU

on:
workflow_dispatch:
schedule:
- cron: "0 12 * * 0"

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

jobs:
iwyu_ubuntu_2204:
runs-on: ubuntu-latest
container: ghcr.io/acts-project/ubuntu2204_clang:v41
steps:
- name: Install git lfs and llvm dev
run: apt-get update && apt-get install -y git-lfs llvm-dev libclang-dev clang

- name: Get IWYU source
uses: actions/checkout@v3
with:
repository: include-what-you-use/include-what-you-use
ref: clang_14
path: iwyu

- name: Build IWYU
run: >
mkdir iwyu-build iwyu-install &&
cmake -B iwyu-build -S iwyu
-DCMAKE_PREFIX_PATH=/usr/lib/llvm-14
-DCMAKE_INSTALL_PREFIX=iwyu-install &&
cmake --build iwyu-build --target install
- name: Get Acts source
uses: actions/checkout@v3
with:
path: acts
submodules: true
lfs: true

- name: Configure Acts
run: >
mkdir acts-build acts-install &&
cmake -B acts-build -S acts
-DCMAKE_EXPORT_COMPILE_COMMANDS=ON
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_CXX_FLAGS=-Werror
-DCMAKE_CXX_STANDARD=17
-DCMAKE_INSTALL_PREFIX=acts-install
-DACTS_BUILD_EVERYTHING=ON
-DACTS_BUILD_ODD=ON
-DACTS_BUILD_EXAMPLES_PYTHON_BINDINGS=ON
-DACTS_BUILD_EXAMPLES_BINARIES=ON
-DACTS_BUILD_EXAMPLES_EDM4HEP=ON
- name: Run IWYU
run: python3 iwyu-install/bin/iwyu_tool.py -p acts-build/ -j2 -- --mapping_file=acts/CI/iwyu/mapping.imp | tee iwyu-output.txt
- name: Filter IWYU output
run: python3 acts/CI/iwyu/filter.py acts/CI/iwyu/filter.yaml iwyu-output.txt iwyu-filtered.txt
- name: Apply IWYU
run: python3 iwyu-install/bin/fix_includes.py < iwyu-filtered.txt

- name: Upload IWYU output
uses: actions/upload-artifact@v3
with:
name: iwyu
path: |
iwyu-output.txt
iwyu-filtered.txt
83 changes: 83 additions & 0 deletions CI/iwyu/filter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import sys
import yaml
import re
import argparse
from collections import namedtuple


Config = namedtuple(
"Config", ["remove_lines", "replace_lines", "ignore_files"], defaults=[[], [], []]
)


class State:
skip_file: bool = False


def parse_config(config: Config):
remove_lines = []
for s in config["remove_lines"]:
remove_lines.append(re.compile(s))

replace_lines = []
for s in config["replace_lines"]:
s, r = list(s.items())[0]
replace_lines.append((re.compile(s), r))

ignore_files = []
for s in config["ignore_files"]:
ignore_files.append(re.compile(s))

return Config(
remove_lines=remove_lines,
replace_lines=replace_lines,
ignore_files=ignore_files,
)


def filter(line: str, config: Config, state: State):
if state.skip_file:
if line.endswith("---\n"):
state.skip_file = False
return None

if line.endswith(" should add these lines:\n"):
for s in config.ignore_files:
if s.search(line):
state.skip_file = True
return None

for s in config.remove_lines:
if s.search(line):
return None

for s, r in config.replace_lines:
if s.search(line):
return s.sub(r, line)

return line


parser = argparse.ArgumentParser()
parser.add_argument("config")
parser.add_argument("input")
parser.add_argument("output")
args = parser.parse_args()

with open(args.config, "r") as config_file:
try:
config = yaml.safe_load(config_file)
config = parse_config(config)
except yaml.YAMLError as exc:
print(exc)
sys.exit(1)

with open(args.input, "r") as input_file, open(args.output, "w") as output_file:
state = State()

for line in input_file:
filtered_line = filter(line, config, state)
if filtered_line is not None:
output_file.write(filtered_line)

sys.exit(0)
27 changes: 27 additions & 0 deletions CI/iwyu/filter.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
remove_lines:
# ignore unexiting std
- "^#include <new>"
- "^#include <bits/"
- "^#include <ext/"
# ignore Eigen
- "^(- )?#include [<\"](src|Eigen)/"
- "namespace Eigen {"
# ignore boost
- "^(- )?#include <boost/"
# don remove ipp
- "^- #include [<\"].*\\.ipp"

replace_lines:
- "^#include <assert\\.h>": "#include <cassert>"
- "^#include <stddef\\.h>": "#include <cstddef>"
- "^#include <math\\.h>": "#include <cmath>"
- "^#include <limits\\.h>": "#include <climits>"
- "^#include <unistd\\.h>": "#include <cunistd>"
- "^#include <stdint\\.h>": "#include <cstdint>"
- "^#include <stdlib.h>": "#include <cstdlib>"
# don use ipp
- "^#include ([<\"].*)\\.ipp": "#include \\1.hpp"

ignore_files:
- ".*FpeMonitor\\.[hc]pp"
- ".*thirdparty/"
3 changes: 3 additions & 0 deletions CI/iwyu/mapping-boost.imp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
{ include: ["@<<boost/histogram/.*>", "private", "<boost/histogram.hpp>", "public"] },
]
4 changes: 4 additions & 0 deletions CI/iwyu/mapping-eigen.imp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ include: ["@<Eigen/src/Core/.*>", "private", "<Eigen/Dense>", "public"] },
{ include: ["@\"src/Core/.*\"", "private", "<Eigen/Dense>", "public"] }
]
4 changes: 4 additions & 0 deletions CI/iwyu/mapping.imp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[
{ ref: "mapping-boost.imp" },
{ ref: "mapping-eigen.imp" }
]

0 comments on commit 2563d3b

Please sign in to comment.