Organization: OSRF
Contributor: Innocent Pious (GitHub, LinkedIn)
Mentors: Scott Logan (GitHub) and Kimberly McGuire (GitHub)
GSoC project: Add Support for Mixin Composition in Colcon-Mixin
Repository: colcon-mixin
Pull requests: #70 - mixin composition, #71 - merge-order fix
Hey folks ![]()
I’m Innocent Pious, a final-year CS student from Chennai, India. I’ve always enjoyed tinkering with developer tooling, and this summer I got to work on colcon-mixin with OSRF, with Scott Logan and Kimberly McGuire mentoring me.
Things are going well the main feature works end to end and is under review. Figured it’s about time I shared what I’ve been up to, flagged a behavior change, and gathered some feedback before it all lands.
Why this project exists
Mixins let you save a bundle of command-line arguments under a name, so instead of typing out a long colcon build --cmake-args ... every time, you just say --mixin debug. Handy but so far every mixin was a standalone bundle. Mixins couldn’t reference each other.
So if you wanted a “dev” setup that combined your debug flags, ccache config, and test flags, you had to copy-paste the same arguments into every variant. Change one, and you’d have to remember to update it everywhere. This has been a longstanding ask (#39).
The goal here is to let mixins be built out of other mixins kind of like how package managers let one package depend on others.
A quick heads up 
Early on, while poking around the merge logic, I ran into #40: when you pass multiple mixins like colcon build --mixin a b, the arguments weren’t merging the way you’d expect.
For list arguments, they came out backwards. With:
build:
a:
cmake-args: ["-DA=1"]
b:
cmake-args: ["-DB=1"]
colcon build --mixin a b gave you ["-DB=1", "-DA=1"] instead of ["-DA=1", "-DB=1"].
For scalar arguments, there’s a second half worth calling out separately, because it’s the one more likely to quietly change your build: previously the first mixin you listed set the value, and any later mixin’s value was silently skipped. Now the last mixin you list wins. That matches how the list case reads (later flags win downstream) and how most people expect “I listed b after a” to behave but if you’ve got a setup that leaned on the old first-one-wins behavior for something like build-base or parallel-workers, this will shift under you.
Both halves follow the same rule now: merging follows the order you list the mixins in.
PR: #71 (this supersedes #59, my earlier attempt at the same fix if you arrived here from issue #40, #71 is the one to look at)
The main feature: mixin composition
A mixin can now list other mixins under a reserved mixin key:
build:
debug:
cmake-args: ["-DCMAKE_BUILD_TYPE=Debug"]
ccache:
cmake-args: ["-DCMAKE_CXX_COMPILER_LAUNCHER=ccache"]
dev:
mixin: ["debug", "ccache"]
cmake-args: ["-DBUILD_TESTING=ON"]
Now colcon build --mixin dev applies debug, then ccache, then dev’s own arguments.
The rule I went with: references get applied first, so the mixin doing the referencing gets the last word and can override anything it inherits. Command-line arguments still beat all of them.
A few details under the hood:
- Application order is worked out with a depth-first, post-order walk.
- A mixin reached through more than one path is applied once per path deliberate, so last-one-wins stays consistent no matter how the graph is shaped. The tradeoff is that diamond-shaped graphs can produce repeated arguments; deduplication is on the to-do list below.
- Circular references get caught (looking only at the active path, so legitimate re-use isn’t mistaken for a cycle) and reported cleanly with the full path, instead of just hanging.
mixinis now a reserved key inside a mixin definition, and is not treated as an argument to overlay.- Mixins that don’t use the key behave exactly as before the merge-order fix above is the only behavior shift in this series.
PR: #70
A fun little side-adventure: stacked PRs 
Since the composition work sits on top of the merge-order fix, I set these up as stacked PRs - #70 targets #71’s branch instead of master, so the diff on #70 shows only the new composition code rather than both changes tangled together. Once #71 lands, #70 gets retargeted to master and rebased.
GitHub only shipped native stacked pull requests into public preview on July 30th, so this is about as fresh as features get, and I was pretty happy to actually put it to use it kept the two changes cleanly separated and made reviewing each piece way easier. Big thanks to Scott and Kimberly for pointing me toward the workflow; it was new to me and honestly a bit of a git bootcamp getting it wired up
. Kimberly mentioned this might be one of the first uses of stacked PRs across the Open Robotics projects, which was a fun bonus. Happy to share how it’s set up if anyone’s curious!
What’s done so far
- Fixed multi-mixin argument merging so list and scalar values combine in the expected order (#71).
- Added a standalone module that computes the application order for a mixin and its references via depth-first post-order traversal.
- Implemented multi-path re-application to keep last-one-wins consistent across any graph shape.
- Added cycle detection that reports circular references with their full path, plus clean errors for unknown names and malformed
mixinkeys. - Wired composition into
parse_argsso referenced mixins apply first, with command-line args still taking precedence. - Added tests for the ordering algorithm, nested references, scalar overrides, command-line precedence, and error paths.
- Kept full backward compatibility for mixins that don’t use the new key.
What’s left
Still some time left in GSoC. The main remaining bits:
- Add list deduplication so repeated arguments get collapsed cleanly (see the diamond-graph note above).
- Extend
colcon mixin showto display the resolved application order for mixins that reference others, so you can see what a composition expands to without running a build. - Add tests for when the same mixin name is defined across multiple repositories, and document that override behavior.
- Add user-facing docs once things are officially merged (these live over in colcon.readthedocs.org).
Would love your feedback
Mainly on the ordering/override semantics does “referenced mixins first, the one you asked for last” match your intuition? And if you’ve got mixin setups in the wild that you think might trip this up, I’d genuinely love to hear about them so I can turn them into test cases.
The scalar change in #40 is the one I’d most like a sanity check on, since it’s the part that could quietly alter an existing build.
Huge thanks to Scott and Kimberly for all the patient guidance and detailed reviews so far, and to OSRF and the ROS community for being so welcoming. Thanks for reading!