@@ -333,6 +333,11 @@ struct ClosureReadInput {
333333 std::vector<std::filesystem::path> platformDirs; // Android
334334 std::vector<std::string> forceBundle; // Pe: overrides the system list
335335 std::string arch; // MachO: the slice of a fat file
336+ // Pe: names never resolved in `searchDirs.front()`. `place_runtime_dlls`
337+ // passes the copies an earlier placement put beside the program, so that
338+ // each resolves again where it came from instead of shadowing a newer
339+ // version there. `mcpp pack` leaves it empty.
340+ std::vector<std::string> notInFirstDir;
336341};
337342
338343// A name that resolved to a file, and where that file is staged: `dest` is
@@ -377,15 +382,21 @@ ClosureRead read_closure(const ClosureReadInput& in);
377382// program's directory is published beside the program through the staging
378383// primitive, which writes only when the bytes differ. `sources` lists what was
379384// resolved, for the edge's depfile, so that a DLL replaced in its directory is
380- // placed again on the next build; `notes` names each DLL that more than one
381- // directory offers, with the one the search order chose.
385+ // placed again on the next build; `names` lists the DLLs placed, which the
386+ // caller records and passes back as `placedBefore` on the next run, so that a
387+ // copy this function put beside the program is resolved again from its
388+ // directory rather than taken for a file of the program's own; `notes` names
389+ // each DLL that more than one directory offers, with the one the search order
390+ // chose.
382391struct RuntimeDllPlacement {
383392 std::vector<std::filesystem::path> sources;
393+ std::vector<std::string> names;
384394 std::vector<std::string> notes;
385395};
386396std::expected<RuntimeDllPlacement, Error>
387397place_runtime_dlls (const std::filesystem::path& program,
388- const std::vector<std::filesystem::path>& searchDirs);
398+ const std::vector<std::filesystem::path>& searchDirs,
399+ const std::vector<std::string>& placedBefore = {});
389400
390401// Build a Plan from already-resolved inputs. Caller is expected to have
391402// already run `mcpp build` (or equivalent) and pass the resulting
@@ -1351,7 +1362,8 @@ make_tarball(const std::filesystem::path& stagingRoot,
13511362
13521363std::expected<RuntimeDllPlacement, Error>
13531364place_runtime_dlls (const std::filesystem::path& program,
1354- const std::vector<std::filesystem::path>& searchDirs)
1365+ const std::vector<std::filesystem::path>& searchDirs,
1366+ const std::vector<std::string>& placedBefore)
13551367{
13561368 const auto programDir = program.parent_path ();
13571369 auto same_dir = [](const std::filesystem::path& a, const std::filesystem::path& b) {
@@ -1366,6 +1378,7 @@ place_runtime_dlls(const std::filesystem::path& program,
13661378 in.searchDirs .push_back (programDir.empty () ? std::filesystem::path (" ." ) : programDir);
13671379 for (auto const & d : searchDirs)
13681380 if (!same_dir (d, in.searchDirs .front ())) in.searchDirs .push_back (d);
1381+ in.notInFirstDir = placedBefore;
13691382 const auto read = read_closure (in);
13701383
13711384 // The program itself is the one object the caller chose, so a program that
@@ -1385,6 +1398,7 @@ place_runtime_dlls(const std::filesystem::path& program,
13851398 " cannot place '{}' beside '{}': {}" , m.source .string (),
13861399 program.filename ().string (), staged.error ().message )});
13871400 out.sources .push_back (m.source );
1401+ out.names .push_back (m.name );
13881402 // Search order decides between two directories that offer one name,
13891403 // and the decision is stated, because the other copy may be the one
13901404 // the author meant.
@@ -1467,8 +1481,12 @@ ClosureRead read_closure(const ClosureReadInput& in)
14671481 continue ;
14681482 }
14691483 std::optional<std::filesystem::path> hit;
1470- for (auto const & dir : in.searchDirs )
1471- if (is_file (dir / name)) { hit = dir / name; break ; }
1484+ const bool skipFirst = std::ranges::any_of (in.notInFirstDir ,
1485+ [&](const std::string& n) { return lower (n) == lower (name); });
1486+ for (std::size_t d = 0 ; d < in.searchDirs .size (); ++d) {
1487+ if (d == 0 && skipFirst) continue ;
1488+ if (is_file (in.searchDirs [d] / name)) { hit = in.searchDirs [d] / name; break ; }
1489+ }
14721490 if (hit) {
14731491 out.members .push_back ({name, *hit, std::filesystem::path (name)});
14741492 // Transitive: a staged library brings its own needs, and a
0 commit comments