build: integrate clang-tidy into CI

This still has utterly unacceptably bad output format design that I
would not inflict on anyone I like, but it *does* now exist, and you
*can* find the errors in the log.

Future work would obviously be to fix that and integrate the actual
errors into Gerrit using codechecker or so.

Followup issue: #457

Fixes: #147
Change-Id: Ifca22e443d357762125f4ad6bc4f568af3a26c62
This commit is contained in:
jade 2024-08-01 15:02:28 -07:00
parent 6fdb47f0b2
commit f3ef0899c7
3 changed files with 52 additions and 13 deletions

View file

@ -282,6 +282,10 @@
# cheaper x86_64-linux compute in CI. # cheaper x86_64-linux compute in CI.
# It is clangStdenv because clang's sanitizers are nicer. # It is clangStdenv because clang's sanitizers are nicer.
asanBuild = self.packages.x86_64-linux.nix-clangStdenv.override { asanBuild = self.packages.x86_64-linux.nix-clangStdenv.override {
# Improve caching of non-code changes by not changing the
# derivation name every single time, since this will never be seen
# by users anyway.
versionSuffix = "";
sanitize = [ sanitize = [
"address" "address"
"undefined" "undefined"
@ -310,6 +314,17 @@
touch $out touch $out
''; '';
# clang-tidy run against the Lix codebase using the Lix clang-tidy plugin
clang-tidy =
let
nixpkgs = nixpkgsFor.x86_64-linux.native;
inherit (nixpkgs) pkgs;
in
pkgs.callPackage ./package.nix {
versionSuffix = "";
lintInsteadOfBuild = true;
};
# Make sure that nix-env still produces the exact same result # Make sure that nix-env still produces the exact same result
# on a particular version of Nixpkgs. # on a particular version of Nixpkgs.
evalNixpkgs = evalNixpkgs =

View file

@ -28,6 +28,8 @@
libcpuid, libcpuid,
libseccomp, libseccomp,
libsodium, libsodium,
lix-clang-tidy ? null,
llvmPackages,
lsof, lsof,
lowdown, lowdown,
mdbook, mdbook,
@ -67,6 +69,8 @@
# Turn compiler warnings into errors. # Turn compiler warnings into errors.
werror ? false, werror ? false,
lintInsteadOfBuild ? false,
# Not a real argument, just the only way to approximate let-binding some # Not a real argument, just the only way to approximate let-binding some
# stuff for argument defaults. # stuff for argument defaults.
__forDefaults ? { __forDefaults ? {
@ -144,6 +148,7 @@ let
(fileset.fileFilter (f: lib.strings.hasPrefix "nix-profile" f.name) ./scripts) (fileset.fileFilter (f: lib.strings.hasPrefix "nix-profile" f.name) ./scripts)
]; ];
in in
assert (lintInsteadOfBuild -> lix-clang-tidy != null);
stdenv.mkDerivation (finalAttrs: { stdenv.mkDerivation (finalAttrs: {
inherit pname version; inherit pname version;
@ -156,12 +161,13 @@ stdenv.mkDerivation (finalAttrs: {
topLevelBuildFiles topLevelBuildFiles
functionalTestFiles functionalTestFiles
] ]
++ lib.optionals (!finalAttrs.dontBuild || internalApiDocs) [ ++ lib.optionals (!finalAttrs.dontBuild || internalApiDocs || lintInsteadOfBuild) [
./doc ./doc
./misc ./misc
./src ./src
./COPYING ./COPYING
] ]
++ lib.optionals lintInsteadOfBuild [ ./.clang-tidy ]
) )
); );
}; };
@ -175,7 +181,7 @@ stdenv.mkDerivation (finalAttrs: {
"doc" "doc"
]; ];
dontBuild = false; dontBuild = lintInsteadOfBuild;
mesonFlags = mesonFlags =
let let
@ -190,14 +196,15 @@ stdenv.mkDerivation (finalAttrs: {
"-Dsandbox-shell=${lib.getExe' busybox-sandbox-shell "busybox"}" "-Dsandbox-shell=${lib.getExe' busybox-sandbox-shell "busybox"}"
] ]
++ lib.optional hostPlatform.isStatic "-Denable-embedded-sandbox-shell=true" ++ lib.optional hostPlatform.isStatic "-Denable-embedded-sandbox-shell=true"
++ lib.optional (finalAttrs.dontBuild) "-Denable-build=false" ++ lib.optional (finalAttrs.dontBuild && !lintInsteadOfBuild) "-Denable-build=false"
++ lib.optional lintInsteadOfBuild "-Dlix-clang-tidy-checks-path=${lix-clang-tidy}/lib/liblix-clang-tidy.so"
++ [ ++ [
# mesonConfigurePhase automatically passes -Dauto_features=enabled, # mesonConfigurePhase automatically passes -Dauto_features=enabled,
# so we must explicitly enable or disable features that we are not passing # so we must explicitly enable or disable features that we are not passing
# dependencies for. # dependencies for.
(lib.mesonEnable "gc" enableGC) (lib.mesonEnable "gc" enableGC)
(lib.mesonEnable "internal-api-docs" internalApiDocs) (lib.mesonEnable "internal-api-docs" internalApiDocs)
(lib.mesonBool "enable-tests" finalAttrs.finalPackage.doCheck) (lib.mesonBool "enable-tests" (finalAttrs.finalPackage.doCheck || lintInsteadOfBuild))
(lib.mesonBool "enable-docs" canRunInstalled) (lib.mesonBool "enable-docs" canRunInstalled)
(lib.mesonBool "werror" werror) (lib.mesonBool "werror" werror)
] ]
@ -230,7 +237,13 @@ stdenv.mkDerivation (finalAttrs: {
] ]
++ lib.optional hostPlatform.isLinux util-linuxMinimal ++ lib.optional hostPlatform.isLinux util-linuxMinimal
++ lib.optional (!officialRelease && buildUnreleasedNotes) build-release-notes ++ lib.optional (!officialRelease && buildUnreleasedNotes) build-release-notes
++ lib.optional internalApiDocs doxygen; ++ lib.optional internalApiDocs doxygen
++ lib.optionals lintInsteadOfBuild [
# required for a wrapped clang-tidy
llvmPackages.clang-tools
# required for run-clang-tidy
llvmPackages.clang-unwrapped
];
buildInputs = buildInputs =
[ [
@ -257,7 +270,10 @@ stdenv.mkDerivation (finalAttrs: {
++ lib.optional hostPlatform.isx86_64 libcpuid ++ lib.optional hostPlatform.isx86_64 libcpuid
# There have been issues building these dependencies # There have been issues building these dependencies
++ lib.optional (hostPlatform.canExecute buildPlatform) aws-sdk-cpp-nix ++ lib.optional (hostPlatform.canExecute buildPlatform) aws-sdk-cpp-nix
++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs; ++ lib.optionals (finalAttrs.dontBuild) maybePropagatedInputs
# I am so sorry. This is because checkInputs are required to pass
# configure, but we don't actually want to *run* the checks here.
++ lib.optionals lintInsteadOfBuild finalAttrs.checkInputs;
nativeCheckInputs = [ expect ]; nativeCheckInputs = [ expect ];
@ -315,7 +331,7 @@ stdenv.mkDerivation (finalAttrs: {
enableParallelBuilding = true; enableParallelBuilding = true;
doCheck = canRunInstalled; doCheck = canRunInstalled && !lintInsteadOfBuild;
mesonCheckFlags = [ mesonCheckFlags = [
"--suite=check" "--suite=check"
@ -327,8 +343,19 @@ stdenv.mkDerivation (finalAttrs: {
# Make sure the internal API docs are already built, because mesonInstallPhase # Make sure the internal API docs are already built, because mesonInstallPhase
# won't let us build them there. They would normally be built in buildPhase, # won't let us build them there. They would normally be built in buildPhase,
# but the internal API docs are conventionally built with doBuild = false. # but the internal API docs are conventionally built with doBuild = false.
preInstall = lib.optional internalApiDocs '' preInstall =
meson ''${mesonBuildFlags:-} compile "$installTargets" (lib.optionalString internalApiDocs ''
meson ''${mesonBuildFlags:-} compile "$installTargets"
'')
# evil, but like above, we do not want to run an actual build phase
+ lib.optionalString lintInsteadOfBuild ''
ninja clang-tidy
'';
installPhase = lib.optionalString lintInsteadOfBuild ''
runHook preInstall
touch $out
runHook postInstall
''; '';
postInstall = postInstall =
@ -396,12 +423,10 @@ stdenv.mkDerivation (finalAttrs: {
mkShell, mkShell,
bashInteractive, bashInteractive,
clang-tools,
clangbuildanalyzer, clangbuildanalyzer,
doxygen, doxygen,
glibcLocales, glibcLocales,
just, just,
llvmPackages,
nixfmt-rfc-style, nixfmt-rfc-style,
skopeo, skopeo,
xonsh, xonsh,
@ -454,7 +479,7 @@ stdenv.mkDerivation (finalAttrs: {
++ [ (lib.mesonBool "enable-pch-std" stdenv.cc.isClang) ]; ++ [ (lib.mesonBool "enable-pch-std" stdenv.cc.isClang) ];
packages = packages =
lib.optional (stdenv.cc.isClang && hostPlatform == buildPlatform) clang-tools lib.optional (stdenv.cc.isClang && hostPlatform == buildPlatform) llvmPackages.clang-tools
++ [ ++ [
# Why are we providing a bashInteractive? Well, when you run # Why are we providing a bashInteractive? Well, when you run
# `bash` from inside `nix develop`, say, because you are using it # `bash` from inside `nix develop`, say, because you are using it

View file

@ -109,7 +109,6 @@ static std::string printHash32(const Hash & hash)
std::string printHash16or32(const Hash & hash) std::string printHash16or32(const Hash & hash)
{ {
assert(hash.type);
return hash.to_string(hash.type == htMD5 ? Base16 : Base32, false); return hash.to_string(hash.type == htMD5 ? Base16 : Base32, false);
} }