System designTroubleshooting

Vision SDK undefined reference: fix a compiler mismatch at link time

Undefined reference to a vision SDK constructor while its enum constants compile is a compiler mismatch; match the SDK build's toolchain and bitness to fix.

LumaSpec Vision11 min read Share on LinkedIn

On this page 8 sections
  1. 01An enum compiles because the header is all it needs
  2. 02Likely causes, ranked for a Windows vision build
  3. 03Worked example: 32-bit MinGW GCC 4.8 against vc12 import libraries
  4. 04The fix, picked by the side you control
  5. 05When the usual answer is wrong
  6. 06Prevention: read the build folder before the link line
  7. 07Where the fault hides in a vision build
  8. 08Questions

You include the SDK header, build one test line, and the compiler is happy — then the first constructor call dies at link time with an undefined reference to a function you never wrote. The pattern has a signature: an assignment from an SDK enumerator compiles cleanly while every class method from the same header fails. That split tells you within a minute whether you are missing a library or linking a build your toolchain cannot use. This guide is for engineers wiring a vendor vision SDK into a C++ application on Windows, on a desktop or on a vision controller.

You will run the one test that separates the fault families, walk a compiler-mismatch case end to end with the reasoning shown, and leave with the matching rules — compiler family, word size, release — that make the link succeed the first time.

An enum compiles because the header is all it needs

An enumerator such as an activation-mode constant is a compile-time value. The compiler reads it from the header and folds the integer into your object file; no library ever supplies it. That is why int mode = Recognizer::SIGMOID_SYM; builds with the include paths alone. (Recognizer here and below stands in for the SDK's classifier class; substitute the name your own header shows.)

A constructor is the opposite case. The header only declares it, and the machine code lives in the SDK's binary libraries. The linker takes every decorated name your object files reference and searches the objects and libraries on the link line for one definition. When none appears, GCC's linker prints undefined reference; the MSVC linker words the same fault as an unresolved external symbol. The message therefore localizes the problem before you touch a flag: the header side is correct, the implementation side is not. The cousin failure differs in kind. An undefined identifier means the compiler never saw the name at all — the trap embedded-C developers meet as a CCS C compiler undefined-identifier error.

Likely causes, ranked for a Windows vision build

Four causes explain nearly every undefined reference thrown at a vendor vision SDK on Windows. Work down the table. Rank 1 leads because vision vendors build their Windows binaries on the MSVC toolchain, so GCC projects hit the ABI wall on the first class they touch.

Rank Cause Test Fix
1 SDK binaries built by another compiler: MSVC import libraries in a MinGW GCC build Build folder names a toolset your kit does not use, e.g. vc12 under a MinGW kit; C functions link, C++ class methods do not Link a build from your own toolchain family (worked example below)
2 Word-size mismatch: 32-bit kit against 64-bit libraries, or the reverse Linker prints skipping incompatible for each library file Match x86 to x86 and x64 to x64, independently of compiler family
3 The module defining the class is absent from the link line Adding the owning library removes exactly that one error List libraries so each dependent precedes its dependencies
4 Headers from one release, binaries from another The exact decorated name in the message exists in no shipped import library (nm, objdump or dumpbin list exports) Reinstall so headers and binaries come from one release

Ranks 1 and 2 look identical in the log — every symbol undefined — so let the messages separate them. A word-size mismatch usually announces itself with skipping incompatible lines before the errors; an ABI mismatch stays silent and never matches. A build whose halves were produced under different switches fails as a cousin instead: an OPC UA C++ SDK HTTPS build-flag mismatch has the same root — one project linking binaries that disagree about how they were built.

Worked example: 32-bit MinGW GCC 4.8 against vc12 import libraries

Inputs. The application kit is MinGW GCC 4.8 with a 32-bit (x86) target. The SDK on disk offers build\x86\vc12 and build\x64\vc12: the vc12 token marks an MSVC toolset build, and x86/x64 marks word size. The code under test uses illustrative names for the SDK's classifier:

// Recognizer and LayerSpec stand in for the SDK's classifier class and its
// layer-structure type; substitute the names your own header shows.
int mode = Recognizer::SIGMOID_SYM;   // int, folded in from the header: compiles
Recognizer* net = new Recognizer(layers, Recognizer::SIGMOID_SYM, 1.0, 1.0);
// link time: undefined reference to `Recognizer::Recognizer(LayerSpec const*, int, double, double)'

Rule in words. A linker resolves a reference only when a binary on the link line exports a decorated name identical, character for character, to the one your object file requests. GCC decorates C++ names with the Itanium ABI scheme; MSVC decorates the same declaration in its own scheme, and for a class constructor the two schemes never produce the same string.

Matching, step by step.

  1. Word size: the kit is 32-bit, the folder is x86 — match.
  2. Compiler family: the kit is GCC, the folder token vc12 is MSVC — no match.
  3. Export scan: the import libraries under x86\vc12 export MSVC-decorated names, constructors among them, while your object file requests an Itanium-shaped name such as _ZN10RecognizerC1EPK9LayerSpecidd. Zero strings in common.
  4. Repeat the scan over every other SDK module: none carries GCC-decorated code, which is why appending every library in the folder leaves the error unchanged.

Result. No ordering, subset or repetition of these binaries can resolve the symbol. The fault is the build selection, not the flags.

Decision and threshold. The moment the SDK's build folder names a toolset your kit does not use — vc12 under a MinGW kit is the textbook case — stop editing the link line and change one side of the equation. Rebuild the SDK from its published sources with your own toolchain, take the vendor's MinGW-compatible build of the same release, or move the application to the MSVC toolset the folder targets. Where the SDK also exposes a flat C interface, prefer it: extern "C" functions carry no class layout, so their import library links from either compiler.

The fix, picked by the side you control

  1. You control the toolchain. Move the application to the SDK's toolset — an MSVC kit when the folder says vc12. Vendors publish and maintain MSVC builds first on Windows, so this is usually the shortest path to a clean link.
  2. You must keep GCC. Rebuild the SDK from source with your own MinGW compiler and word size, or take the vendor's MinGW-compatible build of the same release when one exists. Pin it the way any SDK version pinned across a Docker build has to be held in place; a silent update re-introduces the mismatch.
  3. Neither side can move. Write a thin shim. MinGW GCC cannot link an MSVC-built C++ DLL directly, but a C interface — extern "C" functions wrapping the classes — is the one contract both compilers honor on Windows.
  4. Re-check word size separately. Even a same-family build fails across bitness, with skipping incompatible in the log; point the link line at the folder that matches the kit.

Decision per case. A GCC prototype headed for controller deployment: standardize on one family end to end before the first sprint, not after. A mixed team where one developer needs GCC: put that developer on the C interface. A legacy GCC codebase that cannot move: budget one build of the SDK from source and freeze it.

When the usual answer is wrong

Three reflexes each waste an afternoon:

  • Link every library in the folder. This fixes only the absent-module row of the table. Against an ABI or word-size fault no binary in the set carries a matching implementation, so the error outlives every addition and the link grows slower each round.
  • Wrap the header in extern "C". The block changes how your code is compiled, not how the library was. MSVC-compiled class methods keep their decoration whatever your headers declare; only code genuinely built as C crosses the gap.
  • Upgrade the SDK and retry. A newer release refreshes the decorated names but keeps the compiler family, so the constructor fails again on the first call. Family and release are separate coordinates; fix the one that is wrong.
  • Name the four coordinates before linking: compiler family (MSVC or MinGW GCC), word size (x86, 32-bit, or x64, 64-bit), configuration (release or debug) and release version. The kit must match the first two, and all four must come from one install.
  • Let the folder label the build for you. A toolset token such as vc12 names the compiler family; x86 or x64 names the word size. Match the kit to those tokens, not to the machine you happen to sit at.
  • Keep headers and binaries from one release. Mixing releases changes decorated names quietly, and version skew fails the same way as the plugin case in Robot vision plugin missing: match the plugin version to the program.
  • Plan the deployment machine with the same family and word size as the build machine, and ship the SDK's runtime files with your executable. A link-time fix that ends in a startup error is its own case, walked through in Vision application startup error: diagnose missing DLLs.

Where the fault hides in a vision build

Vendor code reaches your linker through two doors. Frame grabbers take the classic one: a CoaXPress card such as the MV-GX1008 ships an acquisition SDK whose import libraries you link like any third-party binary, so every rule above applies from the first day of the project. A CXP-6 link carries up to 6.25 Gbit/s per lane, so these cards typically drive line-scan or high-resolution area cameras — exactly the setups whose SDKs are large, C++-heavy and built on MSVC.

Frame grabbersHikrobot MV-GX1008 Octo CXP-6 Frame GrabberMV-GX1008
Interface
CoaXPress
$1,949.00View partBuild a system with it

GigE and USB3 cameras usually skip the linker: the driver loads their transport module by file name, so the same coordinates fail later as a load error instead of an undefined reference. That runtime territory is mapped in Camera acquisition backend compatibility troubleshooting, and the case where the vendor's own viewer works while your code does not is laid out in Frame grabber SDK support: why one viewer works and another fails. If the inspection will finally run on a dedicated controller rather than a desktop tower, pick one now: a vision controller such as the MV-VC3301H-128G66 is an Intel Core i3 machine to your toolchain, and building for it with the family and word size you validated on the bench avoids a second surprise at deployment.

Vision controllersHikrobot MV-VC3301H-128G66 I3-8100, 8GB+128G SSD, No PoE, PCIe expansion supported, Incl. VM6200Pro licenseMV-VC3301H-128G66
LAN ports
5+ LAN ports
USB 3 ports
3-4 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$2,419.00View partBuild a system with it

Cross-architecture work stretches the same rule further. An ARM64 target rejects x86 builds of the same SDK for the same reason a 64-bit linker rejects 32-bit objects, a case walked through in ARM64 machine vision acquisition: fix the binary layer. On Linux the neighboring traps are CMake dependency order and position-independent code, covered in C++ camera SDK linking errors: diagnose CMake dependencies and CMake -fPIC relocation errors when linking a vision SDK. For the widest map of the message itself, start at Camera SDK undefined reference: diagnose C++ linker errors.

Decision, in one line: an enum that compiles proves the header; a constructor that fails indicts the binary. Read the folder tokens, match compiler family and word size, and the reference resolves without touching a flag. When the fix turns into a hardware decision — which controller and frame grabber the SDK build can live with — the frame grabbers category shortlists the acquisition cards your build assumes, and every order includes free expert support for exactly this kind of question. More build-side fault walks sit on the systems topic page.

Questions

Can a MinGW build ever link an MSVC-built C++ vision SDK?

Not directly. The two compilers decorate C++ names differently and lay out classes differently, so no exported name ever matches and the linker reports every class method as undefined. The bridge is a plain C interface: extern "C" functions or a thin C shim library carry no class layout, so either compiler can link them. Otherwise rebuild the SDK with your toolchain or build your application with the SDK's toolset.

Why did adding every SDK library to the link line not help?

Because none of those binaries contains an implementation your object file can bind to. Extra libraries only fix an undefined reference when the missing symbol genuinely lives in one of them — the absent-module case. Against a compiler-family or word-size mismatch, every file in the folder is equally foreign, so the message survives and each addition slows the link.

How do I list the symbols an import library actually exports?

On a GCC toolchain run nm or objdump against the import library; on an MSVC toolchain use dumpbin with the exports flag. Compare the decorated name quoted in the undefined-reference message with that list. A differently shaped name means the binary came from another compiler; a missing exact name means headers and binaries come from different releases.

Does the same matching rule apply to cameras that load at runtime?

The rule is the same and the failure just moves in the day. GigE and USB3 cameras load their transport module by file name, so a compiler or bitness mismatch appears as a failed load or a missing plugin rather than a linker message. Check the same four coordinates: family, word size, configuration, release.

Which SDK build do I choose for a vision controller deployment?

The build whose folder tokens match your kit: the toolset token names the compiler family and x86 or x64 names the word size. Pick the family the vendor keeps current — on Windows that is usually the MSVC line — and keep the deployment controller on the same family and word size as the machine you build and test on.