System designTroubleshooting

Fix shared library error 7: file not found in vision software

Shared library error 7 means file not found: the loader never opened your .so. Walk the Linux search order, then test path, name, dependencies and permissions.

LumaSpec Vision9 min read Share on LinkedIn

On this page 8 sections
  1. 01What error 7 does and does not tell you
  2. 02Six causes in order of probability
  3. 03Worked example: libAdditionc.so with the path hardcoded
  4. 04Fix it so it stays fixed
  5. 05Where the fixed build runs
  6. 06When the library opens but the call still fails
  7. 07The decisions, line by line
  8. 08Questions

You compiled a small C++ wrapper into a .so, pointed your vision software at it, and the runtime answers error 7, file not found — while ls shows the file sitting exactly where you said. The message means one narrow thing: the loader never opened what the node asked it to open. This page gives you the loader's real search order, a test for each of the six causes behind this error, and a deployment layout that keeps the library findable on a vision controller after the next reboot.

What error 7 does and does not tell you

When the library-call node runs, your software hands the operating system loader (dlopen) a single string taken from the node's configuration. Error 7 wraps a failed open, and three different faults hide under it. The string may not name an existing file. The file may exist while one of the files it depends on does not. The file may exist and still be unusable by this process. What it does not mean is a missing function: that failure appears later, with a different message, after the file has loaded.

The loader resolves a bare file name in a fixed order:

  1. an absolute path — open exactly that string, no search at all
  2. the directories in LD_LIBRARY_PATH
  3. the cache /etc/ld.so.cache, rebuilt by ldconfig
  4. the default directories /lib and /usr/lib

Step 1 is the one people forget. With an absolute path configured, the cache and the environment are never consulted, which is why an added line in /etc/ld.so.conf cannot rescue a hardcoded path. The loader prints its own diagnosis in a terminal; vision software usually swallows it. The terminal-side workflow is in Linux vision shared library errors: diagnose missing dependencies.

Six causes in order of probability

Work down the list and stop at the first test that fails.

  1. The path string is not the path you think. Text pasted from a report or spreadsheet can carry a trailing newline or carriage return, a tilde stays unexpanded inside the node, and a relative path resolves against the development environment's working directory rather than your build folder. Test: quote the exact string in a terminal — ls -l "/opt/wrapper/libAdditionc.so" — and treat any ls error as the same failure the node hit. The quoting trap is the same one behind GenTL CTI file path errors.
  2. The name-based search cannot see your folder. This cause only applies when the node holds a bare file name. An LD_LIBRARY_PATH exported in your shell reaches only programs launched from that shell, and an entry in /etc/ld.so.conf does nothing until ldconfig rebuilds the cache. Test: ldconfig -p | grep -i addition, and, for the running process, strings /proc/1234/environ | grep LD_LIBRARY_PATH, with the process's numeric ID in place of 1234.
  3. A dependency of the library is missing. The loader opens your .so and every library it lists in one operation; one absent dependency fails the whole open, and the wrapper reports file not found although your file exists. Test: ldd /opt/wrapper/libAdditionc.so — every line must end in a real path, and a "not found" line names the true culprit.
  4. Wrong architecture. A 32-bit build cannot load into a 64-bit process, and an x86-64 build cannot load on an ARM board; the refusal often surfaces as the same not-found error. Test: file libAdditionc.so next to uname -m on the machine that runs the software.
  5. Permissions. The runtime user needs read on the file and the execute bit on every directory along the path; a copy made as root under a restrictive umask can lock the service account out. Test: namei -l /opt/wrapper/libAdditionc.so prints every component's permissions. The triage pattern is the same as in Linux camera device permissions: video and media node checks.
  6. The file is not a shared object. A static archive (.a), a Windows DLL copied across, or an interrupted build. One line of file output settles it.

Worked example: libAdditionc.so with the path hardcoded

Inputs, as the case was reported: a wrapper around a simple C++ addition function, built as libAdditionc.so; the node holds a hardcoded full path (call it /opt/wrapper/libAdditionc.so here and substitute yours); ls confirms the file at that path; the folder was also added to /etc/ld.so.conf; error 7 is unchanged.

Rule, in words: a hardcoded absolute path makes the loader open exactly that string — no LD_LIBRARY_PATH, no cache — so the fault sits in the string itself, in a dependency, or in the file's usability. The ld.so.conf entry is irrelevant to this load path and can be crossed off first.

The checks, with what each outcome proves:

  1. Retype the string inside double quotes in a terminal: ls -l "/opt/wrapper/libAdditionc.so". If a file manager finds the file but quoted ls does not, the node's string carries hidden characters. Fix: retype the path in the node's configuration dialog instead of pasting it.
  2. ldd /opt/wrapper/libAdditionc.so | grep "not found". Empty output clears every dependency; one hit names the package to install before the wrapper can load.
  3. file /opt/wrapper/libAdditionc.so. The architecture printed must match uname -m on the machine running the vision software. A mismatch means one rebuild, not more debugging.
  4. namei -l /opt/wrapper/libAdditionc.so. Every directory on the way needs the x bit for the runtime user, and the file needs r.

Result and decision. Four clean outputs mean the library opens, so the error came from a second copy of the node with an old path. Any hit maps to exactly one fix: retype the string, install the missing dependency, rebuild for the right architecture, or set the bits (644 on the file, x on each directory). Carry away this rule: with an absolute path, /etc/ld.so.conf and LD_LIBRARY_PATH are never the cause; with a bare file name, they are the first two things to check.

Fix it so it stays fixed

Two layouts work; pick one and stay with it.

  • Absolute path in the node, pointing into a versioned directory such as /opt/vision/lib. Nothing in the environment can break it, which suits a single controller you manage. Type the string once by hand and leave it alone.
  • Bare name from /usr/local/lib. Copy the runtime .so there, run sudo ldconfig, and confirm ldconfig -p | grep addition lists it. The name the loader then looks up is the library's SONAME, not the name on your build line: readelf -d libAdditionc.so | grep SONAME. If it prints libAdditionc.so.1, either name the deployed file that or add the link ln -s libAdditionc.so libAdditionc.so.1. This layout suits several applications sharing one library.

After any edit under /etc/ld.so.conf.d, run ldconfig and check ldconfig -p before retesting; the loader reads only the cache. Write the path, symbol and calling convention into the project notes so the next rebuild cannot move them silently — the reference on documenting library-call nodes makes a usable checklist.

Where the fixed build runs

The .so loads into the same machine that grabs camera images and runs the inspection, so the controller's processor decides which build you compile. Run uname -m on the unit before you build, and keep development and deployed builds in different directories. A wrapper plus a handful of dependencies is small — typically a few hundred kB — so deployment stays a two-command job.

An entry controller covers a single-camera station:

Vision controllersHikrobot MV-VC2140-128G40-1T VC2100 Vision Controller, N97, 8GB+128G SSD+ 1THDDMV-VC2140-128G40-1T
LAN ports
3-4 LAN ports
USB 3 ports
2 USB 3 ports
Light outputs
4 built-in channels
Memory
8 GB
$1,679.00View partBuild a system with it

A cell with several cameras needs more LAN ports:

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

The MV-VC2140-128G40-1T runs an Intel N-series processor with 8 GB of memory and four built-in light channels; the MV-VC3301H-128G66 moves up to an Intel Core i3 with 5+ LAN ports and includes the VM6200Pro license. Either way the deployment is the same: copy, set the path or the cache, then call the addition function once as a smoke test before the line starts.

When the library opens but the call still fails

A "function not found in library" message is past this page: the loader opened the file, so path, name, dependencies and permissions are already right. The node cannot find the symbol. The name is misspelled, the C++ compiler decorated it — declare the wrapper function extern "C" so the name stays plain — or the calling convention set in the node does not match the build. Fix those in the node's dialog, not on disk.

Once calls go through, watch memory. A wrapper that allocates image buffers on every call leaks until the process dies, and the discipline is the same as when preventing memory leaks when calling a vision library from C#.

The decisions, line by line

  • Error 7 with an absolute path configured: run the four checks — quoted ls, ldd, file, namei — and fix the single line that fails.
  • Error 7 with a bare file name: sudo ldconfig first, then the launching process's LD_LIBRARY_PATH, then the SONAME.
  • Function not found after a clean load: the node's symbol name and calling convention.
  • Hardware for the runtime: the vision controllers category, the build-a-system configurator, and more Linux fixes on the systems topic page.
ComputersVision controllers

Vision computers and fanless industrial PCs

190 models · from $1,119.00

Questions

Do I need to run ldconfig after editing /etc/ld.so.conf.d?

Yes. The loader never reads the conf files themselves; it reads the cache at /etc/ld.so.cache. Add a one-line .conf holding your directory path, run sudo ldconfig, then confirm with ldconfig -p. Until the cache lists the entry, a name-based load keeps failing. Two limits to remember: a cache entry cannot fix a hardcoded absolute path, and a long-running process that started before the rebuild keeps its old view.

Why does the library load from my terminal but not in the deployed runtime?

The two processes run with different environments. An LD_LIBRARY_PATH exported in a shell reaches only that shell's children, while a program started by a desktop launcher or a service manager begins without it. Inspect the running process with strings /proc/1234/environ | grep LD_LIBRARY_PATH, substituting the process's numeric ID for 1234. The durable fix is to place the library in /usr/local/lib and run ldconfig, which removes the environment dependency entirely.

How do I find the exact file name the loader asks for?

Ask the binaries. readelf -d yourapplication | grep NEEDED lists every dependency recorded at link time, and readelf -d yourlib.so | grep SONAME shows the name embedded in your own library. If the SONAME is libAdd.so.1 while the deployed file is libAdd.so, the open keeps failing until the file carries that name or a symlink supplies it. ldd resolves the same names against the current system.

Must I rebuild the wrapper after an update of the vision software?

Not for the load step: the loader's search rules do not change with an application update. What breaks quietly is the binary interface. If the SDK headers changed, a wrapper compiled against the old headers can still load and then crash or return wrong values. Rebuild whenever the SDK version changes, and bump your library's version number when a function signature changes so old and new builds can coexist.

Does Linux search the current directory for a .so like Windows does?

No. The loader never searches the current working directory, so a library sitting next to your executable stays invisible until you name it. Adding . to LD_LIBRARY_PATH works but lets any file of that name in any directory load, a real hazard on a shared controller. Prefer an absolute path in the node, or /usr/local/lib with ldconfig.