Skip to content

Commit c649ca2

Browse files
committed
Fix for custom-builds
1 parent 20731a2 commit c649ca2

File tree

2 files changed

+95
-19
lines changed

2 files changed

+95
-19
lines changed

onlinejudge_verify/languages/rust.py

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,9 @@ def from_dep_kind(cls, kind: str):
8787
for dep in next(n['deps'] for n in metadata['resolve']['nodes'] if n['id'] == main_package['id']):
8888
if _need_dev_deps(main_target) or any(k['kind'] is None for k in dep['dep_kinds']):
8989
dependencies[DependencyNamespace.NORMAL_DEVELOPMENT][dep['name']] = packages_by_id[dep['pkg']]
90-
if any(k['kind'] == ['build'] for k in dep['dep_kinds']):
90+
if any(k['kind'] == 'build' for k in dep['dep_kinds']):
9191
dependencies[DependencyNamespace.BUILD][dep['name']] = packages_by_id[dep['pkg']]
9292

93-
# Decides whether to include `main_package` itself.
94-
# Note that cargo-udeps does not detect it if it is unused.
95-
# https://github.com/est31/cargo-udeps/pull/35
96-
depends_on_main_package_itself = not _is_lib_or_proc_macro(main_target) and any(map(_is_lib_or_proc_macro, main_package['targets']))
97-
9893
# If `cargo_udeps_toolchain` is present, collects packages that are "unused" by `target`.
9994
unused_packages = defaultdict(set)
10095
if cargo_udeps_toolchain is not None:
@@ -124,14 +119,22 @@ def from_dep_kind(cls, kind: str):
124119
#
125120
# - those detected by cargo-udeps
126121
# - those come from Crates.io or Git repositories (e.g. `proconio`, other people's libraries including `ac-library-rs`)
122+
123+
# `main_package` should always be included.
124+
# Note that cargo-udeps does not detect it if it is unused.
125+
# https://github.com/est31/cargo-udeps/pull/35
126+
depended_packages = [main_package]
127+
for dependency_namespace, values in dependencies.items():
128+
for depended_package in values.values():
129+
if depended_package['id'] not in unused_packages[dependency_namespace] and not depended_package['source']:
130+
depended_packages.append(depended_package)
131+
127132
ret = common_result
128-
depended_packages = [(DependencyNamespace.NORMAL_DEVELOPMENT, main_package)] if depends_on_main_package_itself else []
129-
depended_packages.extend((dependency_namespace, package) for dependency_namespace, dependencies in dependencies.items() for package in dependencies.values())
130-
for dependency_namespace, depended_package in depended_packages:
131-
if depended_package['id'] in unused_packages[dependency_namespace] or depended_package['source']:
132-
continue
133-
depended_target = next(filter(_is_lib_or_proc_macro, depended_package['targets']), None)
134-
if depended_target:
133+
134+
for depended_package in depended_packages:
135+
depended_targets = [t for t in depended_package['targets'] if t != main_target and (_is_build(t) or _is_lib_or_proc_macro(t))]
136+
assert len(depended_targets) <= 2
137+
for depended_target in depended_targets:
135138
related_source_files = _related_source_files(basedir, _cargo_metadata_by_manifest_path(pathlib.Path(depended_package["manifest_path"])))
136139
ret |= _source_files_in_same_targets(pathlib.Path(depended_target['src_path']).resolve(strict=True), related_source_files)
137140
return sorted(ret)
@@ -168,12 +171,13 @@ def _related_source_files(basedir: pathlib.Path, metadata: Dict[str, Any]) -> Di
168171
#
169172
# - https://github.com/rust-lang/cargo/blob/rust-1.49.0/src/cargo/core/compiler/fingerprint.rs#L1979-L1997
170173
# - https://github.com/rust-lang/cargo/blob/rust-1.49.0/src/cargo/core/compiler/fingerprint.rs#L1824-L1830
171-
dep_info_paths = sorted(
172-
pathlib.Path(metadata['target_directory'], 'debug', 'examples' if _is_example(target) else 'deps').glob(f'{target["name"].replace("-", "_")}-*.d'),
173-
key=lambda p: p.stat().st_mtime_ns,
174-
reverse=True,
175-
)
176-
for dep_info_path in dep_info_paths:
174+
if _is_build(target):
175+
dep_info_paths = pathlib.Path(metadata['target_directory'], 'debug', 'build').rglob(f'{_crate_name(target)}-*.d')
176+
elif _is_example(target):
177+
dep_info_paths = pathlib.Path(metadata['target_directory'], 'debug', 'examples').glob(f'{_crate_name(target)}-*.d')
178+
else:
179+
dep_info_paths = pathlib.Path(metadata['target_directory'], 'debug', 'deps').glob(f'{_crate_name(target)}-*.d')
180+
for dep_info_path in sorted(dep_info_paths, key=lambda p: p.stat().st_mtime_ns, reverse=True):
177181
with open(dep_info_path) as file:
178182
dep_info = file.read()
179183
for line in dep_info.splitlines():
@@ -355,6 +359,14 @@ def _ensure_target(metadata: Dict[str, Any], src_path: pathlib.Path) -> Dict[str
355359
return target
356360

357361

362+
def _crate_name(target: Dict[str, Any]) -> bool:
363+
return target['name'].replace('-', '_')
364+
365+
366+
def _is_build(target: Dict[str, Any]) -> bool:
367+
return target['kind'] == ['custom-build']
368+
369+
358370
def _is_lib_or_proc_macro(target: Dict[str, Any]) -> bool:
359371
return target['kind'] in [['lib'], ['proc-macro']]
360372

tests/test_rust.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,70 @@ def test_mono_package(self) -> None:
275275
actual = sorted(RustLanguage(config=None).list_dependencies(tempdir / 'examples' / 'aizu-online-judge-itp1-1-a.rs', basedir=tempdir))
276276
self.assertEqual(actual, expected)
277277

278+
def test_build_dependencies(self) -> None:
279+
files = {
280+
pathlib.Path('rust-toolchain'): textwrap.dedent("""\
281+
1.42.0
282+
""").encode(),
283+
pathlib.Path('Cargo.toml'): textwrap.dedent("""\
284+
[workspace]
285+
members = ["crates/*"]
286+
""").encode(),
287+
pathlib.Path('crates', 'a', 'Cargo.toml'): textwrap.dedent("""\
288+
[package]
289+
name = "a"
290+
version = "0.0.0"
291+
edition = "2018"
292+
293+
[build-dependencies]
294+
b = { path = "../b" }
295+
""").encode(),
296+
pathlib.Path('crates', 'a', 'build.rs'): textwrap.dedent("""\
297+
use std::{env, fs, path::PathBuf};
298+
299+
fn main() {
300+
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
301+
fs::write(out_dir.join("message.txt"), b::MESSAGE).unwrap();
302+
}
303+
""").encode(),
304+
pathlib.Path('crates', 'a', 'src', 'lib.rs'): textwrap.dedent("""\
305+
pub fn print_message() {
306+
println!("{}", include_str!(concat!(env!("OUT_DIR"), "/message.txt")));
307+
}
308+
""").encode(),
309+
pathlib.Path('crates', 'b', 'Cargo.toml'): textwrap.dedent("""\
310+
[package]
311+
name = "b"
312+
version = "0.0.0"
313+
edition = "2018"
314+
""").encode(),
315+
pathlib.Path('crates', 'b', 'src', 'lib.rs'): textwrap.dedent("""\
316+
pub static MESSAGE: &str = "hi";
317+
""").encode(),
318+
}
319+
320+
with tests.utils.load_files_pathlib(files) as tempdir:
321+
322+
def build_src_path(package_name: str) -> pathlib.Path:
323+
return tempdir / 'crates' / package_name / 'build.rs'
324+
325+
def lib_src_path(package_name: str) -> pathlib.Path:
326+
return tempdir / 'crates' / package_name / 'src' / 'lib.rs'
327+
328+
for src_path in [build_src_path('a'), lib_src_path('a')]:
329+
actual = RustLanguage(config=None).list_dependencies(src_path, basedir=tempdir)
330+
generated_file = next((tempdir / 'target' / 'debug' / 'build').rglob('message.txt'))
331+
expected = sorted([build_src_path('a'), lib_src_path('a'), lib_src_path('b'), generated_file])
332+
self.assertEqual(actual, expected)
333+
334+
expected = [generated_file]
335+
actual = RustLanguage(config=None).list_dependencies(generated_file, basedir=tempdir)
336+
self.assertEqual(actual, expected)
337+
338+
expected = [lib_src_path('b')]
339+
actual = sorted(RustLanguage(config=None).list_dependencies(lib_src_path('b'), basedir=tempdir))
340+
self.assertEqual(actual, expected)
341+
278342

279343
class TestRustVerification(unittest.TestCase):
280344
def test_success(self) -> None:

0 commit comments

Comments
 (0)