Linking C dynamic library non-standard location

575 views
Skip to first unread message

Dan...@basereality.com

unread,
Jul 16, 2016, 11:22:25 AM7/16/16
to golang-nuts
Hi, 

Can anyone tell me what I'm doing wrong when building a go program that uses the ImageMagick library that has been installed to a non-standard location.

What I think I'm seeing is that the program builds, but a flag telling the program to look in the non-standard location for the dynamic library isn't set _somewhere_ and so the program fails to be able to locate the library.

Steps to reproduce are:

Configure ImageMagick to install to a non-standard directory and build it:
# ./configure --prefix="/temp/imagemagick-temp" --without-magick-plus-plus --without-perl --disable-openmp --with-gvc=no
# make install

Add the pkgconfig directory to PKG_CONFIG_PATH so that pkg-config can find it.
# export PKG_CONFIG_PATH=/temp/imagemagick-temp/lib/pkgconfig

Check that pkg-config is happy and can find it:
# pkg-config --cflags --libs MagickWand MagickCore
-DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6  -L/temp/imagemagick-temp/lib -lMagickWand-6.Q16 -lMagickCore-6.Q16

Build the program and capture all output:
# go build -v -x debug.go > debug_build.txt 2>&1

Attempt to run it:
# ./debug
./debug: error while loading shared libraries: libMagickWand-6.Q16.so.2: cannot open shared object file: No such file or directory

I've also run the program through strace to capture all system calls, and that capture is below. It shows that the program isn't looking in the right place for the libary file. 

What do I need to do to make the program be able to find the library when it's in that custom location? 

cheers
Dan

p.s. in case it matters I'm using "go version go1.6.2 linux/amd64" on Centos6.4


----debug.go
package main

/*
#cgo !no_pkgconfig pkg-config: MagickWand MagickCore
#include <wand/MagickWand.h>
*/
import "C"
import "fmt"

type KernelInfoType int

const (
KERNEL_UNDEFINED     KernelInfoType = C.UndefinedKernel
)

func main() {
fmt.Println("Hello world")
}
-----------


----debug_build.txt
WORK=/tmp/go-build568335569
command-line-arguments
mkdir -p $WORK/command-line-arguments/_obj/
mkdir -p $WORK/command-line-arguments/_obj/exe/
cd /home/github/golang/goworkspace/src/debug
pkg-config --cflags MagickWand MagickCore
pkg-config --libs MagickWand MagickCore
CGO_LDFLAGS="-g" "-O2" "-L/temp/imagemagick-temp/lib" "-lMagickWand-6.Q16" "-lMagickCore-6.Q16" /home/github/golang/go/pkg/tool/linux_amd64/cgo -objdir $WORK/command-line-arguments/_obj/ -importpath command-line-arguments -- -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -I $WORK/command-line-arguments/_obj/ debug.go
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -I $WORK/command-line-arguments/_obj/ -g -O2 -o $WORK/command-line-arguments/_obj/_cgo_main.o -c $WORK/command-line-arguments/_obj/_cgo_main.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -I $WORK/command-line-arguments/_obj/ -g -O2 -o $WORK/command-line-arguments/_obj/_cgo_export.o -c $WORK/command-line-arguments/_obj/_cgo_export.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -I $WORK/command-line-arguments/_obj/ -g -O2 -o $WORK/command-line-arguments/_obj/debug.cgo2.o -c $WORK/command-line-arguments/_obj/debug.cgo2.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -o $WORK/command-line-arguments/_obj/_cgo_.o $WORK/command-line-arguments/_obj/_cgo_main.o $WORK/command-line-arguments/_obj/_cgo_export.o $WORK/command-line-arguments/_obj/debug.cgo2.o -g -O2 -L/temp/imagemagick-temp/lib -lMagickWand-6.Q16 -lMagickCore-6.Q16
/home/github/golang/go/pkg/tool/linux_amd64/cgo -objdir $WORK/command-line-arguments/_obj/ -dynpackage main -dynimport $WORK/command-line-arguments/_obj/_cgo_.o -dynout $WORK/command-line-arguments/_obj/_cgo_import.go
cd $WORK
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -no-pie -c trivial.c
cd /home/github/golang/goworkspace/src/debug
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -o $WORK/command-line-arguments/_obj/_all.o $WORK/command-line-arguments/_obj/_cgo_export.o $WORK/command-line-arguments/_obj/debug.cgo2.o -g -O2 -L/temp/imagemagick-temp/lib -Wl,-r -nostdlib -Wl,--build-id=none
/home/github/golang/go/pkg/tool/linux_amd64/compile -o $WORK/command-line-arguments.a -trimpath $WORK -p main -buildid f97632daf57e18f83c78ba78cc2d1ac8f96a4d1f -D _/home/github/golang/goworkspace/src/debug -I $WORK -pack $WORK/command-line-arguments/_obj/_cgo_gotypes.go $WORK/command-line-arguments/_obj/debug.cgo1.go $WORK/command-line-arguments/_obj/_cgo_import.go
pack r $WORK/command-line-arguments.a $WORK/command-line-arguments/_obj/_all.o # internal
cd .
/home/github/golang/go/pkg/tool/linux_amd64/link -o $WORK/command-line-arguments/_obj/exe/a.out -L $WORK -extld=gcc -buildmode=exe -buildid=f97632daf57e18f83c78ba78cc2d1ac8f96a4d1f $WORK/command-line-arguments.a
cp $WORK/command-line-arguments/_obj/exe/a.out debug
-----------




----debug_strace.txt
execve("./debug", ["./debug"], [/* 28 vars */]) = 0
brk(0)                                  = 0xc44000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7facec440000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=30417, ...}) = 0
mmap(NULL, 30417, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7facec438000
close(3)                                = 0
open("/lib64/tls/x86_64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib64/tls/x86_64", 0x7fff50c5d9e0) = -1 ENOENT (No such file or directory)
open("/lib64/tls/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib64/tls", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
open("/lib64/x86_64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib64/x86_64", 0x7fff50c5d9e0)   = -1 ENOENT (No such file or directory)
open("/lib64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/lib64", {st_mode=S_IFDIR|0555, st_size=12288, ...}) = 0
open("/usr/lib64/tls/x86_64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/tls/x86_64", 0x7fff50c5d9e0) = -1 ENOENT (No such file or directory)
open("/usr/lib64/tls/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/tls", {st_mode=S_IFDIR|0555, st_size=4096, ...}) = 0
open("/usr/lib64/x86_64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib64/x86_64", 0x7fff50c5d9e0) = -1 ENOENT (No such file or directory)
open("/usr/lib64/libMagickWand-6.Q16.so.2", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/usr/lib64", {st_mode=S_IFDIR|0555, st_size=20480, ...}) = 0
writev(2, [{"./debug", 7}, {": ", 2}, {"error while loading shared libra"..., 36}, {": ", 2}, {"libMagickWand-6.Q16.so.2", 24}, {": ", 2}, {"cannot open shared object file", 30}, {": ", 2}, {"No such file or directory", 25}, {"\n", 1}], 10./debug: error while loading shared libraries: libMagickWand-6.Q16.so.2: cannot open shared object file: No such file or directory
) = 131
exit_group(127)                         = ?
+++ exited with 127 +++

-----------

Ian Lance Taylor

unread,
Jul 16, 2016, 1:08:59 PM7/16/16
to Dan...@basereality.com, golang-nuts
On Sat, Jul 16, 2016 at 6:20 AM, <Dan...@basereality.com> wrote:
>
> Can anyone tell me what I'm doing wrong when building a go program that uses
> the ImageMagick library that has been installed to a non-standard location.
>
> What I think I'm seeing is that the program builds, but a flag telling the
> program to look in the non-standard location for the dynamic library isn't
> set _somewhere_ and so the program fails to be able to locate the library.
>
> Steps to reproduce are:
>
> Configure ImageMagick to install to a non-standard directory and build it:
> # ./configure --prefix="/temp/imagemagick-temp" --without-magick-plus-plus
> --without-perl --disable-openmp --with-gvc=no
> # make install
>
> Add the pkgconfig directory to PKG_CONFIG_PATH so that pkg-config can find
> it.
> # export PKG_CONFIG_PATH=/temp/imagemagick-temp/lib/pkgconfig
>
> Check that pkg-config is happy and can find it:
> # pkg-config --cflags --libs MagickWand MagickCore
> -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16
> -I/temp/imagemagick-temp/include/ImageMagick-6 -L/temp/imagemagick-temp/lib
> -lMagickWand-6.Q16 -lMagickCore-6.Q16

I don't see anything in this output that will tell the program where
to find the shared library. I would expect this to fail the same way
if you were building a C program that used the library.

My guess is that you need to either pass -R /temp/imagemagick-temp/lib
to the linker, which you can do by setting CGO_LDFLAGS, or you need to
add that directory to the list of directories that the dynamic linker
searches--see `man ldconfig`.

Ian

Dan...@basereality.com

unread,
Jul 16, 2016, 2:40:45 PM7/16/16
to golang-nuts, Dan...@basereality.com
Hi Ian,


On Saturday, 16 July 2016 18:08:59 UTC+1, Ian Lance Taylor wrote:
 
My guess is that you need to either pass -R /temp/imagemagick-temp/lib
to the linker, which you can do by setting CGO_LDFLAGS,

I get the same result when using CGO_CFLAGS and CGO_LDFLAGS rather than pkg-config. Building with:

export CGO_CFLAGS="-DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6"
export CGO_LDFLAGS="-L/temp/imagemagick-temp/lib -lMagickWand-6.Q16 -lMagickCore-6.Q16"
go build -v -x -tags no_pkgconfig debug.go > debug_build_with_flags.txt 2>&1

gives the same error.


> I don't see anything in this output that will tell the program where 
> to find the shared library. 

My understanding is that it was extract from the pkg-config information and passed as the -L flag CGO_LDFLAGS e.g. CGO_LDFLAGS="-g" "-O2" "-L/temp/imagemagick-temp/lib"

However as that doesn't work, perhaps my understanding is wrong.

cheers
Dan


-------
WORK=/tmp/go-build032396311
command-line-arguments
mkdir -p $WORK/command-line-arguments/_obj/
mkdir -p $WORK/command-line-arguments/_obj/exe/
cd /home/github/golang/goworkspace/src/debug
CGO_LDFLAGS="-L/temp/imagemagick-temp/lib" "-lMagickWand-6.Q16" "-lMagickCore-6.Q16" /home/github/golang/go/pkg/tool/linux_amd64/cgo -objdir $WORK/command-line-arguments/_obj/ -importpath command-line-arguments -- -I $WORK/command-line-arguments/_obj/ -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 debug.go
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -I $WORK/command-line-arguments/_obj/ -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -o $WORK/command-line-arguments/_obj/_cgo_main.o -c $WORK/command-line-arguments/_obj/_cgo_main.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -I $WORK/command-line-arguments/_obj/ -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -o $WORK/command-line-arguments/_obj/_cgo_export.o -c $WORK/command-line-arguments/_obj/_cgo_export.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -I $WORK/command-line-arguments/_obj/ -DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16 -I/temp/imagemagick-temp/include/ImageMagick-6 -o $WORK/command-line-arguments/_obj/debug.cgo2.o -c $WORK/command-line-arguments/_obj/debug.cgo2.c
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -o $WORK/command-line-arguments/_obj/_cgo_.o $WORK/command-line-arguments/_obj/_cgo_main.o $WORK/command-line-arguments/_obj/_cgo_export.o $WORK/command-line-arguments/_obj/debug.cgo2.o -L/temp/imagemagick-temp/lib -lMagickWand-6.Q16 -lMagickCore-6.Q16
/home/github/golang/go/pkg/tool/linux_amd64/cgo -objdir $WORK/command-line-arguments/_obj/ -dynpackage main -dynimport $WORK/command-line-arguments/_obj/_cgo_.o -dynout $WORK/command-line-arguments/_obj/_cgo_import.go
cd $WORK
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -no-pie -c trivial.c
cd /home/github/golang/goworkspace/src/debug
gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -o $WORK/command-line-arguments/_obj/_all.o $WORK/command-line-arguments/_obj/_cgo_export.o $WORK/command-line-arguments/_obj/debug.cgo2.o -L/temp/imagemagick-temp/lib -Wl,-r -nostdlib -Wl,--build-id=none
/home/github/golang/go/pkg/tool/linux_amd64/compile -o $WORK/command-line-arguments.a -trimpath $WORK -p main -buildid f97632daf57e18f83c78ba78cc2d1ac8f96a4d1f -D _/home/github/golang/goworkspace/src/debug -I $WORK -pack $WORK/command-line-arguments/_obj/_cgo_gotypes.go $WORK/command-line-arguments/_obj/debug.cgo1.go $WORK/command-line-arguments/_obj/_cgo_import.go
pack r $WORK/command-line-arguments.a $WORK/command-line-arguments/_obj/_all.o # internal
cd .
/home/github/golang/go/pkg/tool/linux_amd64/link -o $WORK/command-line-arguments/_obj/exe/a.out -L $WORK -extld=gcc -buildmode=exe -buildid=f97632daf57e18f83c78ba78cc2d1ac8f96a4d1f $WORK/command-line-arguments.a
cp $WORK/command-line-arguments/_obj/exe/a.out debug

-------





Ian Lance Taylor

unread,
Jul 16, 2016, 3:05:26 PM7/16/16
to Dan...@basereality.com, golang-nuts
On Sat, Jul 16, 2016 at 11:40 AM, <Dan...@basereality.com> wrote:
>
> On Saturday, 16 July 2016 18:08:59 UTC+1, Ian Lance Taylor wrote:
>
>>
>> My guess is that you need to either pass -R /temp/imagemagick-temp/lib
>> to the linker, which you can do by setting CGO_LDFLAGS,
>
>
> I get the same result when using CGO_CFLAGS and CGO_LDFLAGS rather than
> pkg-config. Building with:
>
> export CGO_CFLAGS="-DMAGICKCORE_HDRI_ENABLE=0 -DMAGICKCORE_QUANTUM_DEPTH=16
> -I/temp/imagemagick-temp/include/ImageMagick-6"
> export CGO_LDFLAGS="-L/temp/imagemagick-temp/lib -lMagickWand-6.Q16
> -lMagickCore-6.Q16"
> go build -v -x -tags no_pkgconfig debug.go > debug_build_with_flags.txt 2>&1
>
> gives the same error.

I'm suggesting that you need an additional option: -R
/temp/imagemagick-temp/lib. You need to set the runtime library
search path to point to the right directory.

Ian

Dan...@basereality.com

unread,
Jul 16, 2016, 5:10:52 PM7/16/16
to golang-nuts, Dan...@basereality.com
Hi Ian,

On Saturday, 16 July 2016 20:05:26 UTC+1, Ian Lance Taylor wrote:

I'm suggesting that you need an additional option: -R
/temp/imagemagick-temp/lib.  You need to set the runtime library
search path to point to the right directory.


Thanks Ian, 

The command:

go build -ldflags "-r /temp/imagemagick-temp/lib" debug.go 

produces an executable that finds the libraries correctly.

Do you know if it's possible to set this option in an environment variable, so that it isn't needed to be passed on each command line operation?

cheers
Dan

Lars Seipel

unread,
Jul 16, 2016, 6:01:01 PM7/16/16
to Dan...@basereality.com, golang-nuts
On Sat, Jul 16, 2016 at 02:10:38PM -0700, Dan...@basereality.com wrote:
> Do you know if it's possible to set this option in an environment variable,
> so that it isn't needed to be passed on each command line operation?

Ian mentioned another way to achieve your goal: add the directory to the
list of paths the runtime linker is looking for libraries. On CentOS
(and most other Linux systems, too) there's a directory
/etc/ld.so.conf.d where you can drop a snippet listing your path on a
single line. Alternatively, you can put it in the LD_LIBRARY_PATH
environment variable.

Note that these are knobs for controlling runtime behaviour. They need
to be in place when you run the program, not when compiling.

Ian Lance Taylor

unread,
Jul 16, 2016, 6:03:57 PM7/16/16
to Dan...@basereality.com, golang-nuts

See the linker docs for LD_RUN_PATH.

Ian

Reply all
Reply to author
Forward
0 new messages