Loading Chilkat library in PureBasic

When using OpenLibrary() in PureBasic to load a shared library (DLL on Windows, .so on Linux, or .dylib on macOS), the library must be located in a directory where the OS’s dynamic linker can find it.

Each Chilkat .pb file, such as CkCrypt2.pb, contains the following fragment for loading the Chilkat shared library:

  CompilerSelect #PB_Compiler_OS
    CompilerCase #PB_OS_Windows
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        CkCacheLibId.i = OpenLibrary(#PB_Any, "chilkatPb32.dll")
      CompilerElse
        CkCacheLibId.i = OpenLibrary(#PB_Any, "chilkatPb.dll")
      CompilerEndIf
    CompilerCase #PB_OS_MacOS
      CompilerIf #PB_Compiler_Processor = #PB_Processor_arm64
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPbM1.dylib")
      CompilerElse
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPb.dylib")
      CompilerEndIf
    CompilerCase #PB_OS_Linux
      ; Note: The full path of the .so shared library will be required when running from a compiled executable on Linux.
      ; See https://www.purebasic.fr/english/viewtopic.php?t=79882
      CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPb32.so")
      CompilerElseIf #PB_Compiler_Processor = #PB_Processor_arm32
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPbArm32.so")
      CompilerElseIf #PB_Compiler_Processor = #PB_Processor_arm64
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPbArm64.so")
      CompilerElse
        CkCacheLibId.i = OpenLibrary(#PB_Any, "libchilkatPb.so")
      CompilerEndIf
  CompilerEndSelect

If OpenLibrary fails, your application will crash with the error: Invalid memory access. (write error at address 0)

Here’s a breakdown by platform:


Windows (.dll)

OpenLibrary() will search in this order:

  1. Full path if you pass it.
    OpenLibrary(0, "C:\libs\example.dll")
  2. If only a filename is given:
    • The current working directory
    • The directory of the executable
    • The system folders:
      • C:\Windows\System32
      • C:\Windows\SysWOW64 (for 32-bit apps on 64-bit systems)
      • Folders in the system PATH environment variable

Windows Tips:

  • You can temporarily add a path using:
    SetCurrentDirectory("C:\MyLibs\")
    OpenLibrary(0, "example.dll")

Linux (.so)

OpenLibrary() uses the system dynamic linker. The .so file must be:

  1. In a directory listed in the environment variable LD_LIBRARY_PATH, or
  2. In a standard system location like:
    • /usr/lib
    • /usr/local/lib
    • /lib
  3. In the current working directory (in some cases)

Linux Tips:

  • Set LD_LIBRARY_PATH at runtime:
    export LD_LIBRARY_PATH=/home/user/mylibs:$LD_LIBRARY_PATH
    ./myprogram
  • Or give the full path:
    OpenLibrary(0, "/home/user/mylibs/libexample.so")

macOS (.dylib)

macOS uses DYLD_LIBRARY_PATH and search paths similar to Linux.

OpenLibrary() will search:

  1. Full path, if provided
  2. Environment variable DYLD_LIBRARY_PATH
  3. System folders:
    • /usr/lib
    • /usr/local/lib
  4. App bundle's internal folders (if bundled)

macOS Tips:

  • Set DYLD_LIBRARY_PATH before running:
    export DYLD_LIBRARY_PATH=/Users/me/mylibs
    ./myapp
  • Or use:
    OpenLibrary(0, "/Users/me/mylibs/libexample.dylib")

Summary Table

OS Can Load From Env Variable
Windows CWD, EXE dir, System32, PATH "%PATH%"
Linux CWD, "/usr/lib", custom paths "LD_LIBRARY_PATH"
macOS CWD, "/usr/lib", app bundle paths "DYLD_LIBRARY_PATH"

Best Practice:

  • Use full or relative paths in OpenLibrary() when possible.
  • Don’t assume the current directory is always searched (especially on macOS or newer Linux distros with stricter security settings).
  • If you distribute your app with shared libs, place them in a known location relative to the executable and resolve paths at runtime.