Skip to content

artifacts dependency rejects duplicate C++ module names across independent executables #732

Description

@julixian

Problem

An executable requested through artifacts is a separate program, but mcpp scans its C++ modules together with the consumer's modules and requires module names to be unique across both programs. This makes otherwise independent executables fail to configure when each has a module with the same name.

Observed with mcpp 2026.9.28.2 while changing a GUI's updater dependency from tools = ["Updater"] to artifacts = ["Updater"]. The GUI uses a core package that compiles boost.ixx, and the updater package also compiled that same boost.ixx for its own executable. mcpp build -p GPPGUI --profile fast-release --configure-only failed with:

error: scanner errors:
  .../Updater/../3rdParty/3rdModule/boost.ixx: module 'boost' is provided by package 'gpp.core' (.../GalTranslPP/../3rdParty/3rdModule/boost.ixx) and by package 'gpp.updater' (.../Updater/../3rdParty/3rdModule/boost.ixx)

Minimal example

app/
  mcpp.toml
  src/common.ixx
  src/main.cpp
updater/
  mcpp.toml
  src/common.ixx
  src/main.cpp

app/mcpp.toml:

[package]
name = "app"
version = "0.1.0"

[dependencies]
updater = { path = "../updater", artifacts = ["updater"] }

[build]
sources = ["src/common.ixx"]
module_extensions = [".ixx"]

[targets.app]
kind = "bin"
main = "src/main.cpp"

updater/mcpp.toml is the same except for the package and target names, and it has no dependency on app:

[package]
name = "updater"
version = "0.1.0"

[build]
sources = ["src/common.ixx"]
module_extensions = [".ixx"]

[targets.updater]
kind = "bin"
main = "src/main.cpp"

Both common.ixx files can contain export module common; export int value() { return 1; }, and both main.cpp files can contain import common; int main() { return value() - 1; }. The two module units belong to different executables and need not import each other. Run mcpp build --configure-only from app/.

The minimal example is extracted from the observed project case; I have not run this reduced directory separately.

Expected behavior

artifacts should build the updater for the consumer's target and profile, while allowing each independent executable to have its own module provider scope (or otherwise isolating the updater's build). The updater's object/BMI should not be linked into the consumer.

Actual behavior / likely cause

scan_packages() collects units from every package and then calls resolve_graph() once. resolve_graph() keys producerOf only by the logical module name and rejects the second provider, without considering which executable owns it. This rejection is understandable for two providers within one executable's import closure, but it also applies across independent executables brought together by an artifacts edge.

The project worked around the conflict by replacing the updater's single import boost; with a Boost header include and removing its duplicate module source. That avoids this particular error but does not address the scope issue.

Related: #711 introduced target-side executable artifacts.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions