Skip to content

#70/fix libsumo in-process start (missing geos DLLs) - #237

Open
yunlishao-vibe wants to merge 2 commits into
dev_v0.9.0from
feature/70_libsumo_start
Open

#70/fix libsumo in-process start (missing geos DLLs)#237
yunlishao-vibe wants to merge 2 commits into
dev_v0.9.0from
feature/70_libsumo_start

Conversation

@yunlishao-vibe

Copy link
Copy Markdown
Contributor

Summary

Makes the libsumo (in-process SUMO) path actually start. The blocker was not libsumo's
initialization logic — it was two missing DLLs that made libsumocpp.dll impossible to load.
This adds them, removes two libtraci-only calls that would have failed immediately afterwards,
and stops the packaging script from publishing a broken artifact again.

ENABLE_LIBSUMO remains off by default — this repairs the opt-in path, it does not switch to it.

Root Cause

CommonLib/libsumo/bin was missing geos_c.dll and its own dependency geos.dll, two
third-party libraries bundled with SUMO's Windows distribution. gdal.dll and spatialite.dll
import geos_c statically, so the whole chain — and therefore libsumocpp.dll — could not load.

The reason it looked like a startup/sequencing bug: TrafficLayer delay-loads libsumocpp.dll
(TrafficLayer.vcxproj <DelayLoadDLLs>, x64 Debug + Release). So nothing fails at process start.
TrafficLayer boots, opens its socket and accepts clients (mainTrafficLayer.cpp:795 runs before
:869). The first call that touches the library is Simulation::start(), so that is where the
loader failure lands — as a Win32 structured exception 0xC06D007E, not a C++ exception.
The try/catch around start() therefore never runs: the process dies with nothing on the console
and nothing in TrafficLayer.err, while already-connected clients sit waiting. That is precisely
the "hang or exit" described in the issue.

start() itself was never at fault. With a loadable build the byte-identical argument list works.

This also explains why the external-process path was unaffected: it uses libtracicpp.dll, which
has only 8 dependencies, all standard Windows ones, and never touches gdal.

Evidence (delay-loaded probe mirroring TrafficHelper.cpp's exact call sequence):

before:  about to call libsumo::Simulation::start() ...
         EXITCODE=-1066598274        <- 0xC06D007E, no catch fired

after:   [OK]    Simulation::start(cmd)  -> API 21, SUMO 1.22.0
         [THROW] Simulation::setOrder(1) -> Multi client support ... not implemented in libsumo
         [OK]    Simulation::step() / Vehicle::getIDList() -> 1 vehicle / close()

Related Issues / Tasks

Closes #70.

Related: #109 (native-deps rolling release) — the published libsumo-1.22.0.zip asset has the
same two DLLs missing, so prebuilt fetches are broken identically. See "Follow-up" below.

Type of Change

  • Bug fix
  • New feature
  • Maintenance / Refactor
  • Documentation
  • Test case / scenario update

Affected Modules / Components

  • CommonLib/libsumo/bin/ — added geos_c.dll (457 KB) and geos.dll (2.5 MB), taken from the
    official SUMO 1.22.0 Windows build, matching the version pinned in dependencies.yaml.
  • CommonLib/TrafficHelper.cpp
    • Dropped setOrder() from the libsumo launch. libsumo rejects it at runtime: "Multi client
      support (including connection switching) is not implemented in libsumo."
      The in-process
      simulation is the only client, so ordering is meaningless.
    • Dropped --num-clients from the libsumo argv (no TraCI server exists in-process), and
      documented that --remote-port must never be added there — it makes SUMO open a real
      TraCI server and block inside start() waiting for a client that never connects.
    • Under ENABLE_LIBSUMO, EnableAutoLaunch: false now fails with an actionable message instead
      of dying inside the library: libsumo embeds the simulation and cannot attach to an externally
      running SUMO (init() is libtraci-only and throws there).
    • Added libsumoPreflight(), which loads libsumocpp.dll explicitly before the first call, so a
      missing dependency becomes a normal catchable error with a clear message rather than a silent
      0xC06D007E death.
    • Corrected the stale "This is the active implementation" comment — ENABLE_LIBSUMO is opt-in
      and commented out; stock builds use libtraci.
  • scripts/dispatch/pack_native_deps.ps1 — verifies the staged bin/ actually loads before packing,
    so an incomplete folder cannot be published as a release asset again.

Test Cases

All measured on this branch; no full CarMaker/VISSIM co-sim was involved.

  1. Dependency completeness — transitive walk over libsumocpp / libsumocppD / libtracicpp /
    libtracicppD (94 modules): missing third-party DLLs went from geos_c.dll to none.
  2. Load test — all four libraries plus gdal.dll and spatialite.dll now load
    (LoadLibraryEx); previously libsumocpp.dll and gdal.dll failed with err=126.
  3. End-to-end call sequence — a C++ probe linked against the vendored libsumocpp.lib and
    delay-loaded exactly as TrafficLayer is, replicating TrafficHelper.cpp's sequence against
    tests/Python/SimpleEchoClient/simple_loop.sumocfg. Before: died at 0xC06D007E. After:
    start() returns SUMO 1.22.0, step() and getIDList() work, close() clean.
    This also empirically confirmed setOrder() and init() throw under libsumo.
  4. Compilation, both configurationsTrafficHelper.cpp compiles clean with ENABLE_LIBSUMO
    defined and undefined. The libsumo branch is not built by default, which is how it rotted;
    it is now known to compile.
  5. Packaging guard — with geos.dll removed the packer refuses (GetLastError=126, exit 1,
    no zip written); with it present the check passes and packing proceeds.
  6. --remote-port hang, characterised — confirmed start() blocks indefinitely; it opens a
    real TraCI server and returned only after an external client attached (21.4 s). Not currently
    passed by the code; documented so it is not added later.

Environment

  • Python version: 3.10.11 (probes only)
  • MATLAB/Simulink/dSPACE version: n/a
  • SUMO version: 1.22.0 (vendored DLLs); SUMO 1.21.0 installed locally for comparison
  • VISSIM version: n/a
  • IPG CarMaker version: n/a

Compiler: MSVC 19.29 (VS 2022), x64.

Checklist

  • Code compiles/runs as expected
  • Tests pass locally
  • Documentation is updated (if applicable)
  • Relevant issues are linked
  • Version-specific changes are noted (if any)

Additional Notes

Follow-up required (not in this PR): the published libsumo-1.22.0.zip on the
fixs-native-deps rolling release is missing the same two DLLs, so anyone fetching prebuilt deps
still gets the broken set. It needs re-packing and re-publishing
(pack_native_deps.ps1 -Component sumo -Publish). That overwrites a public release asset, so it is
left as a deliberate maintainer action rather than folded into this PR.

Scope note — libsumo cannot drive sumo-gui on Windows. Verified in both the Python and C++ APIs:
SUMO warns "Libsumo on Windows does not work with GUI, falling back to plain libsumo" and silently
runs headless (hasGUI() false, no window). The same guard is compiled into the vendored 1.22.0
binaries and into SUMO 1.27, so it is not a version or build-flag issue. Anything needing a visible
network must stay on the libtraci path. #70's acceptance criteria should be read as headless-only.

Priority note. With the #177 fix already on dev_v0.9.0, the shipping libtraci path measures
~1.17 ms/step vs ~0.26 ms/step in-process at N=23 on simple_loop — against a 100 ms/step budget.
libsumo's remaining benefit is therefore small for interactive co-sim and is mainly of interest for
headless batch runs, where the no-GUI limitation costs nothing.

Not verified: a full TrafficLayer.exe run with ENABLE_LIBSUMO enabled end-to-end against
SimpleEchoClient. That needs a complete dispatch build (yaml-cpp was not built in this worktree).
The library-level sequence it depends on is verified above, but the last acceptance-criteria box in
#70 should be ticked by whoever runs the full build.

libsumocpp.dll could not be loaded at all. CommonLib/libsumo/bin was missing
geos_c.dll and its dependency geos.dll, two third-party libraries bundled with
SUMO's own Windows distribution. gdal.dll (and spatialite.dll) import geos_c
statically, so the whole chain failed to load.

Because TrafficLayer delay-loads libsumocpp.dll (TrafficLayer.vcxproj
<DelayLoadDLLs>, x64 Debug+Release), the breakage did not surface at startup.
It surfaced on the first libsumo call - Simulation::start() - as a Win32 loader
exception (0xC06D007E). That is not a C++ exception, so the try/catch around
start() never ran: TrafficLayer died with no console output and nothing in
TrafficLayer.err, after clients had already connected and were waiting. That is
the "hang or exit" reported in #70. start() itself was never at fault; with a
loadable build the identical argument list works.

The external-process path was unaffected because it uses libtracicpp.dll, which
has only 8 dependencies, all standard Windows ones, and never touches gdal.

Changes:

- CommonLib/libsumo/bin: add geos_c.dll + geos.dll from the official SUMO
  1.22.0 Windows build (matches dependencies.yaml). Verified: the transitive
  dependency graph of libsumocpp/libsumocppD/libtracicpp/libtracicppD is now
  complete, and all four load.

- TrafficHelper.cpp: drop setOrder() from the libsumo launch. libsumo rejects it
  at runtime ("Multi client support (including connection switching) is not
  implemented in libsumo"); the in-process simulation is the only client.

- TrafficHelper.cpp: drop --num-clients from the libsumo argv (meaningless with
  no TraCI server) and document that --remote-port must never be added - it makes
  SUMO open a real TraCI server and block inside start() waiting for a client
  that never connects. Measured: start() blocked indefinitely until an external
  client attached, then returned after 21.4s.

- TrafficHelper.cpp: under ENABLE_LIBSUMO, fail with an actionable message when
  EnableAutoLaunch is false. libsumo embeds the simulation and cannot attach to
  an externally running SUMO; init() is libtraci-only and throws there.

- TrafficHelper.cpp: add libsumoPreflight(), which loads libsumocpp.dll
  explicitly before the first call so a missing dependency becomes a normal
  catchable error instead of a silent 0xC06D007E death.

- pack_native_deps.ps1: verify the staged bin/ actually loads before packing.
  The published libsumo-1.22.0.zip has the same missing DLLs, so prebuilt
  fetches are broken identically; this stops a broken asset shipping again.

- Correct the stale "This is the active implementation" comment: ENABLE_LIBSUMO
  is opt-in and commented out; stock builds use libtraci.

ENABLE_LIBSUMO remains off by default. Both configurations compile.
…g them

The previous commit removed --num-clients and setOrder() from the libsumo
launch because libsumo has no TraCI server and rejects setOrder() at runtime.
But SumoSetup.NumClients and SumoSetup.ExecutionOrder are user-facing YAML
keys, so dropping them silently let a config ask for something the build
cannot do while still appearing to run - the same silent-failure class as the
bug this issue is about.

Now:
- NumClients != 1 is a hard error. Additional TraCI clients could never
  connect to an in-process simulation, so the run would be broken anyway;
  fail immediately with the reason and the two ways out.
- ExecutionOrder != 1 warns and continues. With a single in-process client
  ordering is genuinely moot, so it is not worth failing a run over.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant