ld Cannot Find -lcurand | Fix Missing CUDA Link Flags

The ld cannot find -lcurand error means libcurand isn’t on your link path; point to the CUDA lib folder and link again.

If you build CUDA code on Linux, this linker message can stop you cold. The good news is that it’s usually a path or packaging mismatch, not a broken GPU or a bad compiler.

You’ll fix it faster if you treat it like a checklist job. First, prove the library exists on disk. Next, prove your build is passing the right -L search directory. Then, make runtime loading predictable so the binary doesn’t fail after it links.

This article sticks to that flow. You’ll see quick terminal checks, build-system fixes for Make and CMake, and the small details that trip people up when CUDA lives in a non-default folder.

What The Linker Is Telling You

The message comes from the host linker (ld), even if you typed nvcc. When the linker sees -lcurand, it searches its known library directories for a file named like libcurand.so (shared) or libcurand.a (static).

If it can’t find a match, it prints the error and stops. That’s all it means. No deeper mystery. In plain terms, your build asked for cuRAND, yet the linker can’t see where cuRAND lives.

Most failures fall into one bucket:

  • Missing CUDA dev files — You have the GPU driver and nvidia-smi works, yet the cuRAND library files aren’t installed.
  • Wrong CUDA root — Your build assumes /usr/local/cuda, yet your CUDA install lives in a versioned folder or under /usr/lib.
  • Search path not passed — The link step never receives the right -L directory, so it only searches system defaults.
  • Mixed toolchains — Conda, Spack, or a custom compiler wrapper shifts link behavior and hides system libraries.
  • Static vs shared mismatch — Your link line points at a static archive that isn’t present on your machine.

Once you know which bucket you’re in, the fix is usually a two-line change.

Quick Checks That Pinpoint The Real Cause

Do these checks before you edit build files. They tell you whether you’re missing the library, or just missing the path.

Confirm Your CUDA Install Is On The Machine

  1. Run nvcc –version — If the command fails, the CUDA compiler isn’t on your PATH, or CUDA isn’t installed.
  2. Locate nvcc — Use which nvcc to see the active CUDA version when you have multiple installs.
  3. Print CUDA_HOME — Run echo "$CUDA_HOME". If it’s empty, your build may be guessing paths.

A working nvcc still doesn’t prove cuRAND is installed, yet it confirms you’re not chasing a phantom setup.

Find libcurand On Disk

  1. Check the dynamic loader cache — Run ldconfig -p | grep -i curand and see if libcurand.so is listed.
  2. Look in common CUDA lib folders — Check /usr/local/cuda/lib64 and /usr/local/cuda/targets/x86_64-linux/lib.
  3. Search with find if needed — Try sudo find /usr -name "libcurand.so*" and note the directory that contains it.

If you cannot find any libcurand file, you’re dealing with a missing package. If you do find it, you’re one good -L away from a clean link.

Map Your Install Style To The Right Folder

CUDA can land in different places depending on how it was installed. Pick the folder that exists on your machine, not the one you saw in a random snippet.

Install Style Folder To Check Link Flag Pattern
NVIDIA runfile /usr/local/cuda/lib64 -L/usr/local/cuda/lib64 -lcurand
NVIDIA deb/rpm /usr/local/cuda/targets/x86_64-linux/lib -L…/targets/x86_64-linux/lib -lcurand
Distro packages /usr/lib/x86_64-linux-gnu -L/usr/lib/x86_64-linux-gnu -lcurand

Once you know the folder, you can stop guessing and wire it into your build in a way that survives updates.

ld Cannot Find -lcurand When Linking

This section is the “make it link” part. The linker needs two things: a directory that contains libcurand, and the library name. Put both on the final link step.

Fix It In A Makefile Or Plain Command Line

If you link with g++ or clang++, you’ll add the CUDA library directory with -L, then request cuRAND with -lcurand. Keep these on the command that creates the final binary, not the commands that compile object files.

  1. Add the library directory — Use the directory that contains libcurand.so, such as -L/usr/local/cuda/lib64.
  2. Link the library by name — Add -lcurand after your object files.
  3. Keep library order sane — Put libraries after objects so symbol resolution works in one pass.

If you use nvcc as the final linker, the idea stays the same. You still pass -L and -l, and nvcc forwards them to the host linker.

Fix It In CMake Without Hard-Coded Paths

CMake can handle CUDA libraries cleanly when you let it discover CUDA and use imported targets. That avoids scattering raw paths across files.

  1. Enable CUDA in project() — If you compile .cu sources, set your project languages to include CUDA.
  2. Find CUDA packages — Use find_package(CUDAToolkit REQUIRED) so CMake locates headers and libraries.
  3. Link the CUDA target — Add CUDA::curand in target_link_libraries(your_target PRIVATE CUDA::curand).

If you can’t use imported targets, you can still set link directories on a target or pass an absolute path to libcurand.so. It works, but it’s easier to break when CUDA moves.

Fix It When A Python Stack Alters Your Compiler

Conda-style shells can swap compilers and linkers. That can change default search paths and make system CUDA libs “disappear” during linking.

  • Check the active compiler — Run which g++ and g++ --version in the same shell you build from.
  • Print the full link command — Build with verbose output so you can see whether your final link line includes the CUDA -L path.
  • Set one CUDA root — Point CMake or your build scripts at the real CUDA install folder you found on disk.

If you’re stuck in a loop where the same message returns, the usual cause is that you edited one build file, yet a different generator is producing the real link step.

Runtime Loading: Don’t Let The Binary Fail After It Links

Some builds link cleanly and still fail at runtime with a loader message about libcurand.so. That’s a different stage. Link-time search paths decide whether you can build the binary. Runtime search paths decide whether the system can load the shared library when the binary starts.

If CUDA lives outside standard system library folders, you’ll want one of these approaches:

  1. Add an rpath — Link with an rpath like -Wl,-rpath,/usr/local/cuda/lib64 so the loader checks that folder automatically.
  2. Use LD_LIBRARY_PATH for dev shells — Export your CUDA lib directory in your shell profile during development runs.
  3. Register the directory system-wide — Add a file under /etc/ld.so.conf.d, then run sudo ldconfig.

rpath keeps things tidy when you run the same binary across machines with the same CUDA layout. For shared servers with many CUDA versions, a documented install path plus loader config tends to reduce surprises.

Common Causes That Keep The Error Coming Back

When the fix feels like it “should work” and still doesn’t, one detail is usually still off. These checks are fast and often reveal the missing piece.

cuRAND Files Aren’t Installed

You can have working drivers and still lack cuRAND development files. That’s normal on fresh machines and on minimal container images.

  1. Verify cuRAND is present — Use your package manager or CUDA installer logs to confirm the cuRAND library files were installed.
  2. Re-locate libcurand.so — Repeat the disk check after installation and write down the real directory.
  3. Clean old build output — Remove cached build folders so stale link flags don’t mask the new install.

Wrong Architecture Directory

CUDA uses architecture-specific directories like targets/x86_64-linux and targets/aarch64-linux. Linking against the wrong one can make the file “missing” even when it exists elsewhere.

  • Match the targets folder — Use the directory that matches your machine architecture.
  • Watch lib vs lib64 — Many installs store 64-bit libraries in lib64, so linking against lib can fail.
  • Confirm the file type — Run file libcurand.so to ensure it matches your platform.

Static Linking Mix-Ups

Some build setups try static linking and request archives like libcurand_static.a. If that archive isn’t installed, you’ll get a missing-library error even if the shared library exists.

  1. Check for static archives — Look for libcurand_static.a in the same CUDA library directory.
  2. Switch to shared linking — Use -lcurand and link the shared library if static isn’t present.
  3. Add system libs if static is required — Static links often need extra flags like -lpthread and -ldl.

Multiple CUDA Versions Colliding

It’s common to have more than one CUDA version installed. Your PATH may select one version, while your build scripts point at another. That mismatch can produce a link path that looks plausible and still misses the real file.

  1. Print every CUDA-related variable — Check PATH, LD_LIBRARY_PATH, CUDA_HOME, and your build cache values.
  2. Pick one source of truth — Set one CUDA root and make your build read only that value.
  3. Check the /usr/local/cuda symlink — If it points at an old version, update it or stop relying on it.

At this point, if you still see ld cannot find -lcurand, turn on verbose builds and follow the final link command line. It will show which directories are searched and which ones are missing.

Make The Fix Stick In Real Projects

Once your build is clean, lock the fix in so the next machine or CI run doesn’t break. A stable setup makes failures loud and clear, instead of subtle and time-wasting.

Build Hygiene Checklist

  1. Centralize the CUDA path — Store the CUDA install directory in one variable and reuse it across build steps.
  2. Keep a verbose build switch — Make it easy to print the full compile and link commands.
  3. Fail fast when CUDA isn’t found — In CMake, require CUDA discovery and stop with a clear error when it’s missing.
  4. Test a real cuRAND call — Run a small program that creates a generator and produces a few values, not just a compile-only test.

Container Builds And Split Images

Containers are a common place to hit this error. Some images include headers but not libraries, or libraries but not headers. Multi-stage builds can also create a binary that links in the builder stage and fails in the runner stage.

  • Build in a dev image — Use an image that includes CUDA development files and cuRAND.
  • Check dependencies in the runner — Run ldd your_binary and confirm it resolves libcurand.so.
  • Keep runtime paths consistent — If the runner image has CUDA in a different folder, prefer rpath or loader config that matches the runner.

Two Final Sanity Tests

Before you move on, run these tests. They catch the “it links on my box” issue and the “it runs only in my shell” issue.

  1. Relink from scratch — Delete the final binary and run the link step again to confirm the fix is in the build rules.
  2. Confirm loader behavior — Run with LD_DEBUG=libs once and watch where libcurand is loaded from.

Once those pass, you’re done. The next time you see ld cannot find -lcurand, you’ll know exactly what to check first, and you’ll have a fix that won’t crumble the next time CUDA moves folders.