|
4 | 4 |
|
5 | 5 | use std::env;
|
6 | 6 | use std::fs;
|
7 |
| -use std::path::PathBuf; |
| 7 | +use std::path::{Path, PathBuf}; |
8 | 8 | use std::process::Command;
|
9 | 9 | use std::process::ExitCode;
|
10 | 10 |
|
@@ -45,6 +45,14 @@ fn get_subtrees() -> Vec<&'static str> {
|
45 | 45 | ]
|
46 | 46 | }
|
47 | 47 |
|
| 48 | +/// Return the pathspecs to exclude all subtrees |
| 49 | +fn get_pathspecs_exclude_subtrees() -> Vec<String> { |
| 50 | + get_subtrees() |
| 51 | + .iter() |
| 52 | + .map(|s| format!(":(exclude){}", s)) |
| 53 | + .collect() |
| 54 | +} |
| 55 | + |
48 | 56 | fn lint_subtree() -> LintResult {
|
49 | 57 | // This only checks that the trees are pure subtrees, it is not doing a full
|
50 | 58 | // check with -r to not have to fetch all the remotes.
|
@@ -87,6 +95,102 @@ fs:: namespace, which has unsafe filesystem functions marked as deleted.
|
87 | 95 | }
|
88 | 96 | }
|
89 | 97 |
|
| 98 | +fn lint_includes_build_config() -> LintResult { |
| 99 | + let config_path = "./src/config/bitcoin-config.h.in"; |
| 100 | + let include_directive = "#include <config/bitcoin-config.h>"; |
| 101 | + if !Path::new(config_path).is_file() { |
| 102 | + assert!(Command::new("./autogen.sh") |
| 103 | + .status() |
| 104 | + .expect("command error") |
| 105 | + .success()); |
| 106 | + } |
| 107 | + let defines_regex = format!( |
| 108 | + r"^\s*(?!//).*({})", |
| 109 | + check_output(Command::new("grep").args(["undef ", "--", config_path])) |
| 110 | + .expect("grep failed") |
| 111 | + .lines() |
| 112 | + .map(|line| { |
| 113 | + line.split("undef ") |
| 114 | + .nth(1) |
| 115 | + .unwrap_or_else(|| panic!("Could not extract name in line: {line}")) |
| 116 | + }) |
| 117 | + .collect::<Vec<_>>() |
| 118 | + .join("|") |
| 119 | + ); |
| 120 | + let print_affected_files = |mode: bool| { |
| 121 | + // * mode==true: Print files which use the define, but lack the include |
| 122 | + // * mode==false: Print files which lack the define, but use the include |
| 123 | + let defines_files = check_output( |
| 124 | + git() |
| 125 | + .args([ |
| 126 | + "grep", |
| 127 | + "--perl-regexp", |
| 128 | + if mode { |
| 129 | + "--files-with-matches" |
| 130 | + } else { |
| 131 | + "--files-without-match" |
| 132 | + }, |
| 133 | + &defines_regex, |
| 134 | + "--", |
| 135 | + "*.cpp", |
| 136 | + "*.h", |
| 137 | + ]) |
| 138 | + .args(get_pathspecs_exclude_subtrees()) |
| 139 | + .args([ |
| 140 | + // These are exceptions which don't use bitcoin-config.h, rather the Makefile.am adds |
| 141 | + // these cppflags manually. |
| 142 | + ":(exclude)src/crypto/sha256_arm_shani.cpp", |
| 143 | + ":(exclude)src/crypto/sha256_avx2.cpp", |
| 144 | + ":(exclude)src/crypto/sha256_sse41.cpp", |
| 145 | + ":(exclude)src/crypto/sha256_x86_shani.cpp", |
| 146 | + ]), |
| 147 | + ) |
| 148 | + .expect("grep failed"); |
| 149 | + git() |
| 150 | + .args([ |
| 151 | + "grep", |
| 152 | + if mode { |
| 153 | + "--files-without-match" |
| 154 | + } else { |
| 155 | + "--files-with-matches" |
| 156 | + }, |
| 157 | + include_directive, |
| 158 | + "--", |
| 159 | + ]) |
| 160 | + .args(defines_files.lines()) |
| 161 | + .status() |
| 162 | + .expect("command error") |
| 163 | + .success() |
| 164 | + }; |
| 165 | + let missing = print_affected_files(true); |
| 166 | + if missing { |
| 167 | + return Err(format!( |
| 168 | + r#" |
| 169 | +^^^ |
| 170 | +One or more files use a symbol declared in the bitcoin-config.h header. However, they are not |
| 171 | +including the header. This is problematic, because the header may or may not be indirectly |
| 172 | +included. If the indirect include were to be intentionally or accidentally removed, the build could |
| 173 | +still succeed, but silently be buggy. For example, a slower fallback algorithm could be picked, |
| 174 | +even though bitcoin-config.h indicates that a faster feature is available and should be used. |
| 175 | +
|
| 176 | +If you are unsure which symbol is used, you can find it with this command: |
| 177 | +git grep --perl-regexp '{}' -- file_name |
| 178 | + "#, |
| 179 | + defines_regex |
| 180 | + )); |
| 181 | + } |
| 182 | + let redundant = print_affected_files(false); |
| 183 | + if redundant { |
| 184 | + return Err(r#" |
| 185 | +^^^ |
| 186 | +None of the files use a symbol declared in the bitcoin-config.h header. However, they are including |
| 187 | +the header. Consider removing the unused include. |
| 188 | + "# |
| 189 | + .to_string()); |
| 190 | + } |
| 191 | + Ok(()) |
| 192 | +} |
| 193 | + |
90 | 194 | fn lint_doc() -> LintResult {
|
91 | 195 | if Command::new("test/lint/check-doc.py")
|
92 | 196 | .status()
|
@@ -128,6 +232,7 @@ fn main() -> ExitCode {
|
128 | 232 | let test_list: Vec<(&str, LintFn)> = vec![
|
129 | 233 | ("subtree check", lint_subtree),
|
130 | 234 | ("std::filesystem check", lint_std_filesystem),
|
| 235 | + ("build config includes check", lint_includes_build_config), |
131 | 236 | ("-help=1 documentation check", lint_doc),
|
132 | 237 | ("lint-*.py scripts", lint_all),
|
133 | 238 | ];
|
|
0 commit comments