I am trying to create a golang program which will use an external C library.
Before doing complex stuff, I wanted to test the use of SWIG in a small foo example.
I also want to be able to use the "go get" syntax without having to manually run swig. And to take into account that the external C library shall have been built before and can be located anywhere on the machine.
I am using golang 1.12.5 and swig 3.0.12
I have created the following structure:
.
|-- libfoo
| |-- foo.c
| |-- foo.h
| `-- libfoo.so
`-- src
|-- example_test.go
|-- lib.go
`-- libfoo.swig
In the libfoo folder I have a simple shared library. The files contain:
foo.c:
#include "foo.h"
int foo(int c){
return c+1;
};
foo.h
int foo(int c);
That I've compiled it with:
gcc -o ./libfoo.so -fPIC -shared ./foo.c
Then the golang files:
libfoo.swig
%module libfoo
%{
extern int foo(int a);
%}
extern int foo(int a);
lib.go
package libfoo
/*
#cgo LDFLAGS: -L../libfoo -lfoo
*/
import "C"
And finally example_test.go
package libfoo
import (
"testing"
"fmt"
)
func TestFoo(*testing.T) {
i := Foo(1)
fmt.Printf("%v\n",i)
}
When I try to build with "go build -x" It seems that the cgo directives located in the "lib.go" file are not taken into account as I do not see the flag appears in the output. Here is the output
06aa7e308d6:/mnt/data/src# go build -x
WORK=/tmp/go-build551116655
mkdir -p $WORK/b001/
swig -version
cd $WORK
/opt/go/pkg/tool/linux_amd64/compile -o ./b001/_go_.o -trimpath ./b001 -p main -complete -goversion go1.12.5 -D _$WORK -c=4 ./swig_intsize.go
cd /mnt/data/src
swig -go -cgo -intgosize 64 -module libfoo -o $WORK/b001/libfoo_wrap.c -outdir $WORK/b001/ libfoo.swig
CGO_LDFLAGS='"-g" "-O2"' /opt/go/pkg/tool/linux_amd64/cgo -objdir $WORK/b001/ -importpath _/mnt/data/src -- -I $WORK/b001/ -g -O2 ./lib.go $WORK/b001/_libfoo_swig.go
cd $WORK
gcc -fno-caret-diagnostics -c -x c - || true
gcc -Qunused-arguments -c -x c - || true
gcc -fdebug-prefix-map=a=b -c -x c - || true
gcc -gno-record-gcc-switches -c -x c - || true
cd $WORK/b001
TERM='dumb' gcc -I /mnt/data/src -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -o ./_x001.o -c _cgo_export.c
TERM='dumb' gcc -I /mnt/data/src -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -o ./_x002.o -c lib.cgo2.c
TERM='dumb' gcc -I /mnt/data/src -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -o ./_x003.o -c _libfoo_swig.cgo2.c
TERM='dumb' gcc -I /mnt/data/src -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -o ./_x004.o -c libfoo_wrap.c
TERM='dumb' gcc -I /mnt/data/src -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -I ./ -g -O2 -o ./_cgo_main.o -c _cgo_main.c
cd /mnt/data/src
TERM='dumb' gcc -I . -fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=$WORK/b001=/tmp/go-build -gno-record-gcc-switches -o $WORK/b001/_cgo_.o $WORK/b001/_cgo_main.o $WORK/b001/_x001.o $WORK/b001/_x002.o $WORK/b001/_x003.o $WORK/b001/_x004.o -g -O2
# _/mnt/data/src
/tmp/go-build551116655/b001/_x004.o: In function `_wrap_foo_libfoo_0f106433f15c8754':
/tmp/go-build/libfoo_wrap.c:255: undefined reference to `foo'
collect2: error: ld returned 1 exit status
If I set the CGO_LDFLAGS using an environment variable, it works. However I want to be able to just use "go get" without having those variables before.
I don't understand why go does not take my #cgo directive into account.
Did I miss something ?
Someone on the golang github repository has solved my issue.
The solution was to remove the newline between the import "C" directive and the comments containing the #cgo directives.
Related
I want to use the https://github.com/tensaix2j/binacpp (a Binance c++ library) and I'm getting the same error again and again. I changed the MakeFile in the library to the correct paths but yeah... Here is my MakeFile:
libcurl_dir=../lib/libcurl-7.56.0
libcurl_include=${libcurl_dir}/include
libcurl_lib=${libcurl_dir}/lib
jsoncpp_dir=../lib/jsoncpp-1.8.3
jsoncpp_include=${jsoncpp_dir}/include
jsoncpp_src=${jsoncpp_dir}/src
libwebsockets_dir=../lib/libwebsockets-2.4.0
libwebsockets_include=${libwebsockets_dir}/include
libwebsockets_lib=${libwebsockets_dir}/lib
libbinacpp_dir=../lib/libbinacpp
libbinacpp_include=${libbinacpp_dir}/include
libbinacpp_lib=${libbinacpp_dir}/lib
build_dir=../lib/libbinacpp/lib
objects=$(build_dir)/jsoncpp.o $(build_dir)/binacpp_utils.o
$(build_dir)/binacpp_logger.o $(build_dir)/binacpp.o $(build_dir)/binacpp_websocket.o
build_include=../lib/libbinacpp/include
$(build_dir)/libbinacpp.so: $(objects)
g++ -I$(libcurl_include) -I$(jsoncpp_include) I$(libwebsockets_include) \
-L$(libcurl_lib) \
-L$(libwebsockets_lib) \
$(objects) \
-shared \
-lcurl -lcrypto -lwebsockets -fPIC -o $#
# Make a new copy of the header too
cp *.h $(build_include)
$(build_dir)/binacpp.o: binacpp.cpp binacpp.h
g++ -I$(libcurl_include) -I$(jsoncpp_include) -c binacpp.cpp -fPIC -o $(build_dir)/binacpp.o
$(build_dir)/binacpp_websocket.o: binacpp_websocket.cpp binacpp_websocket.h
g++ -I$(libwebsockets_include) -I$(jsoncpp_include) -c binacpp_websocket.cpp -fPIC -o $(build_dir)/binacpp_websocket.o
$(build_dir)/binacpp_logger.o: binacpp_logger.cpp binacpp_logger.h
g++ -c binacpp_logger.cpp -fPIC -o $(build_dir)/binacpp_logger.o
$(build_dir)/binacpp_utils.o: binacpp_utils.cpp binacpp_utils.h
g++ -c binacpp_utils.cpp -fPIC -o $(build_dir)/binacpp_utils.o
$(build_dir)/jsoncpp.o: $(jsoncpp_src)/jsoncpp.cpp
g++ -I$(jsoncpp_include) -c $(jsoncpp_src)/jsoncpp.cpp -fPIC -o $(build_dir)/jsoncpp.o
clean:
rm $(build_dir)/*.o
rm $(build_dir)/*.so
If I'm inserting the paths like:
#include "../../libcurl-7.56.0/include/curl/curl.h"
instead of:
#include <curl/curl.h>
then it works but I cant change it for all includes.
Here's the Tree:
binacpp
-example
-lib
--jsoncpp-1.8.3
--libbinacpp
---include
----binacpp.h (File with include issue)
----binacpp_logger.h
----binacpp_websocket.h
----binacpp_utils.h
---lib
--libcurl-7.56.0
--(here's some other not important stuff)
-src
--MakeFile
--(here's some other not important stuff)
Vulkan SDK hosts a C++ header-only C-wrapped library. Problem is, it is really a heavy header, so it wastes a lot of compilation time.
So I looked into using a make file for my Vulkan project, which I never did before. I decided to programatically generate all the dependencies. Probably I messed up this part as well, making it too difficult to understand.
It does kind of work, probably there is an easier way to do the same thing(s).
Here comes the part I can't really work out with:
I generated all the .o (object) files for my project along with the .gch (precompiled headers)
Then I did the same for the vulkan.hpp and the glfw3.h. (Remember, that's where most of my compilation time is going into).
... And here is where I have several problems about this procedure:
Can I, somehow, force the g++ compiler to use .gch files? The combination of -I, -include doesn't seem to work at all and I cannot even debug what is going on with -H/-M/-MM because i have no output whatsoever from this commands.
I am using MSYS2 MINGW_64 release, if it makes a difference.
I'd be glad if someone could give me a tip or two about make files and, in particular, if there is something I completely misunderstood about the compilation process.
# Methods
define uniq =
$(eval seen :=)
$(foreach _,$1,$(if $(filter $_,${seen}),,$(eval seen += $_)))
${seen}
endef
# Compilation flags
_COMPILER := g++ -std=c++17
_FLAGS_WARNING := -Wall -Wextra -Wshadow
_FLAGS_COMPILE := -g -O0
_FLAGS_VULKAN := -lglfw3 -lvulkan
# Custom Flags
_FLAGS_DEBUG := -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0
# Output
_OUTPUT_NAME := test
# Directories
_TMP_DIR := _tmp
_O_DIR := ${_TMP_DIR}\.o
_GCH_DIR := ${_TMP_DIR}\.gch
_SOURCE_DIR := src
_BUILD_DIR := build
_DEBUG_DIR := ${_BUILD_DIR}\debug
_RELEASE_DIR := ${_BUILD_DIR}\release
# Files
_VULKAN_HPP := C:/VulkanSDK/1.2.148.1/Include/vulkan/vulkan.hpp
_GLFW_HPP := C:/msys64/mingw64/include/GLFW/glfw3.h
# Grouping Files
# .cpp & .o
_CPP_LIST := ${wildcard ${_SOURCE_DIR}/*.cpp ${_SOURCE_DIR}/*/*.cpp}
_CPP_LIST_NAME := ${notdir ${_CPP_LIST}}
_O_LIST := ${addprefix ${_O_DIR}/, ${patsubst %.cpp, %.o, ${_CPP_LIST_NAME}}}
# .hpp & .gch
_HPP_LIST := ${wildcard ${_SOURCE_DIR}/*.hpp ${_SOURCE_DIR}/*/*.hpp} ${_VULKAN_HPP}
_HPP_LIST_NAME := ${notdir ${_HPP_LIST}}
_GCH_LIST := ${addprefix ${_GCH_DIR}/, ${patsubst %.hpp, %.gch, ${_HPP_LIST_NAME}}}
# .h & .gch
_H_LIST := ${_GLFW_HPP}
_H_LIST_NAME := ${notdir ${_H_LIST}}
_C_GCH_LIST := ${addprefix ${_GCH_DIR}/, ${patsubst %.h, %.gch, ${_H_LIST_NAME}}}
_COMPILATION_BUNDLE_CPP = ${_FLAGS_WARNING} ${_FLAGS_COMPILE} ${_FLAGS_VULKAN} ${_FLAGS_DEBUG} -I ${_GCH_DIR}
_COMPILATION_BUNDLE_HPP = ${_FLAGS_COMPILE} -x c++-header ${_FLAGS_DEBUG} -I ${_GCH_DIR}
${_DEBUG_DIR}/${_OUTPUT_NAME}: ${_GCH_LIST} ${_C_GCH_LIST} ${_O_LIST}
${_COMPILER} ${_COMPILATION_BUNDLE_CPP} ${_O_LIST} ${addprefix -include , ${_GCH_LIST}} ${addprefix -include , ${_C_GCH_LIST}} -o $#
vpath %.cpp $(call uniq, ${dir ${_CPP_LIST}})
${_O_DIR}/%.o: %.cpp
${_COMPILER} ${_COMPILATION_BUNDLE_CPP} -c $< -o $#
vpath %.hpp $(call uniq, ${dir ${_HPP_LIST}})
${_GCH_DIR}/%.gch: %.hpp
${_COMPILER} ${_COMPILATION_BUNDLE_HPP} $< -o $#
vpath %.h $(call uniq, ${dir ${_H_LIST}})
${_GCH_DIR}/%.gch: %.h
${_COMPILER} ${_COMPILATION_BUNDLE_HPP} $< -o $#
The execution on a clean project (thus easier to follow along):
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch src/helper/helper.hpp -o _tmp\.gch/helper.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch src/renderer/renderer.hpp -o _tmp\.gch/renderer.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch C:/VulkanSDK/1.2.148.1/Include/vulkan/vulkan.hpp -o _tmp\.gch/vulkan.gch
g++ -std=c++17 -g -O0 -x c++-header -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch C:/msys64/mingw64/include/GLFW/glfw3.h -o _tmp\.gch/glfw3.gch
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch -c src/main.cpp -o _tmp\.o/main.o
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch -c src/helper/helper.cpp -o _tmp\.o/helper.o
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch -c src/renderer/renderer.cpp -o _tmp\.o/renderer.o
g++ -std=c++17 -Wall -Wextra -Wshadow -g -O0 -lglfw3 -lvulkan -D _DEBUG -D _DEBUG_SEVERITY=0 -D _DEBUG_TYPE=0 -I _tmp\.gch _tmp\.o/main.o _tmp\.o/helper.o _tmp\.o/renderer.o -include _tmp\.gch/helper.gch -include _tmp\.gch/renderer.gch -include _tmp\.gch/vulkan.gch -include _tmp\.gch/glfw3.gch -o build\debug/test
Using pre-compiled headers is actually fairly straight forward. It might be easiest to break it down into manual steps. You can even retro fit to an existing project pretty easily. The steps could be:
Create a PCH file including a bunch of std libs or other headers you want to pre-compile. Note: Compile your PCH with the same flags as your other c++ code is compiled with, otherwise it may not work.
Add the include flags for the PCH in your makefile... and that is basically it.
So lets try a practical example:
Start with a source file, src1.cpp and compile it: g++ -I. <other flags> src1.cpp -o src1.o
Create your pch file, call it pch.hpp (or whatever)
Compile your PCH file: g++ -I. <other flags> pch.hpp (same flags as the previous compile). This generates the pch.hpp.gch file.
Now you can use your PCH file in your original compile line: g++ -I. <other flags> src1.cpp -o src1.o -Winvalid-pch -include pch.hpp
Couple of things to note:
If you use -Winvalid-pch warning flag this usually gives you enough information to figure out why the pch is not used (like its missing, bad path, bad options etc...).
Use -include pch.hpp not -include pch.hpp.gch since g++ will figure that out. You can see that retro fitting it is easy - since you just append the include flags to your compiler lines.
If your .gch file is not generated then the code should still compile using the pch.hpp header directly...
i'm trying to use the boost_math libs on OS X (i'm not using Xcode), specifically the one containing the error function
I downloaded and compiled boost_1_60_0 myself (using bootstrap.sh and following the instructions.) I didn't use home-brew or something else, which might be why my installation seems so screwed up.
What i'm trying to include in my Szabo.hpp is this:
#include <boost/math/special_functions/erf.hpp>
My makefile goes like this:
LIB_FLAGS = -L/Documents/boost_1_60_0/stage/lib -lboost_math
ALL_OBJECTS = main.o Gaussienne.o Grille.o Szabo.o
all: $(ALL_OBJECTS)
g++ -o hydrogene $(ALL_OBJECTS) $(LIB_FLAGS)
Gaussienne.o: Gaussienne.cpp
g++ -o Gaussienne.o -c Gaussienne.cpp -W -Wall -ansi
main.o: Gaussienne.hpp Grille.hpp main.cpp Szabo.o
g++ -o main.o -c main.cpp -W -Wall -ansi
Grille.o: Grille.cpp Gaussienne.cpp
g++ -o Grille.o -c Grille.cpp -W -Wall -ansi
Szabo.o: Szabo.cpp Gaussienne.cpp
g++ -o Szabo.o -c Szabo.cpp -W -Wall -ansi
clean:
rm -rf *.o
mrproper: clean
rm -rf hydrogene
I get no linking error from g++, however i got:
In file included from Szabo.cpp:12:
./Szabo.hpp:21:10: fatal error: 'boost/math/special_functions/erf.hpp' file not found
#include <boost/math/special_functions/erf.hpp>
^
1 error generated.
Can you please provide help on how to fix this? Thanks in advance
Ok so apparently likes this, it works:
LIB_FLAGS = -L/Users/devolution/Documents/boost_1_60_0/stage/lib -lboost_math_tr1
I_FLAGS = -I/Users/devolution/Documents/boost_1_60_0/
ALL_OBJECTS = main.o Gaussienne.o Grille.o Szabo.o
all: $(ALL_OBJECTS)
g++ -o hydrogene $(ALL_OBJECTS) $(LIB_FLAGS)
Gaussienne.o: Gaussienne.cpp
g++ -o Gaussienne.o -c Gaussienne.cpp -ansi ${I_FLAGS}
main.o: Gaussienne.hpp Grille.hpp main.cpp Szabo.o
g++ -o main.o -c main.cpp -ansi ${I_FLAGS}
Grille.o: Grille.cpp Gaussienne.cpp
g++ -o Grille.o -c Grille.cpp -ansi ${I_FLAGS}
Szabo.o: Szabo.cpp Gaussienne.cpp
g++ -o Szabo.o -c Szabo.cpp -ansi ${I_FLAGS}
.PHONY: clean mrproper
clean:
rm -rf *.o
mrproper: clean
rm -rf hydrogene
Is there a way to pass I_FLAGS?
You've compiled Boost's separately-compiled libraries, which is great, but you didn't copy the headers to your toolchain's include path. Indeed, most of Boost is comprised of header-only libraries, so this is arguably the more crucial step of installing Boost.
The internet tells me you may be able to find the default header search path with the following command at shell:
gcc -x c++ -v -E /dev/null
(https://stackoverflow.com/a/19852298/560648)
When you find it, copy the distribution's boost subdirectory to it.
And, yes, having home-brew install Boost for you would have been much easier… probably one command!
I am using jenkins for my CI server but i have problems when i want to build the project because jenkins does not recognize the compilation errors.This is my problem:
creating objects directory obj
g++ -I../src -I third-party/cppunit-1.12.1/include -fPIC -g -Wall -c booktest.cpp -o obj/booktest.o
g++ -I../src -I third-party/cppunit-1.12.1/include -fPIC -g -Wall -c reader/bookreadertest.cpp -o obj/reader/bookreadertest.o
g++ -I../src -I third-party/cppunit-1.12.1/include -fPIC -g -Wall -c indexer/indexertest.cpp -o obj/indexer/indexertest.o
indexer/indexertest.cpp: In constructor ‘IndexerTest::IndexerTest()’:
indexer/indexertest.cpp:17:12: error: ‘failMethod’ was not declared in this scope
make: *** [obj/indexer/indexertest.o] Error 1
creating objects directory obj
g++ -I ../src -fPIC -g -Wall -c src/main.cpp -o obj/src/main.o
g++ -o oreallybooks -fPIC -g -Wall obj/src/main.o -L/user/local/lib -L../src/lib -loreally -lm
Finished: SUCCESS
I am using bash files to build and clean the cpp project
I "execute shell" for "build steps" in jenkins and this is the command:
/var/lib/jenkins/jobs/OreallyBooks/workspace/buildProject
"buildProject" is bash file and contains:
!/bin/bash
cd src;
make;
cd ../test;
make;
cd ../ui
make;
Someone can help me please? thanks all
If anything other than the final make fails then the bash script will ignore the error.
You need to set the script to fail on first error
#!/bin/bash -e
Stop on first error
my program compiles nicely for Android, however when I try to copy it to the Android emulator, it gives the following error:
knight666#Katja-Linux /media/Data/Shared/Galaxians $ acpy Galaxians.android
Filename: 'Galaxians.android'
819 KB/s (420657 bytes in 0.501s)
link_image[1638]: 825 could not load needed library 'libstdc++.so.6' for '/system/sbin/Galaxians.android' (load_library[984]: Library 'libstdc++.so.6' not found)CANNOT LINK EXECUTABLE
acpy is a small script I wrote that does the following:
#!/bin/sh
FILEPATH=`dirname $1`
FILENAME=`basename $1 .c`
echo "Filename: '$FILENAME'"
adb push $FILEPATH/$FILENAME /system/sbin/$FILENAME
adb shell chmod 777 /system/sbin/$FILENAME
adb shell /system/sbin/$FILENAME
Here is how I build my application:
oem#androiddev /media/YoghurtGum/Tests/Galaxians $ sudo make
arm-none-linux-gnueabi-g++ -static-libgcc -g -Wall -Werror -O2 -w -I ../../YoghurtGum/src/GLES -I ../../YoghurtGum/src -c src/Alien.cpp -o intermediate/Alien.o
arm-none-linux-gnueabi-g++ -static-libgcc -g -Wall -Werror -O2 -w -I ../../YoghurtGum/src/GLES -I ../../YoghurtGum/src -c src/Bullet.cpp -o intermediate/Bullet.o
arm-none-linux-gnueabi-g++ -static-libgcc -g -Wall -Werror -O2 -w -I ../../YoghurtGum/src/GLES -I ../../YoghurtGum/src -c src/Game.cpp -o intermediate/Game.o
arm-none-linux-gnueabi-g++ -static-libgcc -g -Wall -Werror -O2 -w -I ../../YoghurtGum/src/GLES -I ../../YoghurtGum/src -c src/Player.cpp -o intermediate/Player.o
arm-none-linux-gnueabi-gcc
-Wl,--entry=main,
-dynamic-linker=/system/bin/linker,
-rpath-link=/home/oem/android-ndk-r3/build/platforms/android-5/arch-arm/usr/lib,
-rpath=../../YoghurtGum/lib/Android,
-L/home/oem/android-ndk-r3/build/platforms/android-5/arch-arm/usr/lib
-nostdlib
-lstdc++
intermediate/Alien.o
intermediate/Bullet.o
intermediate/Game.o
intermediate/Player.o
../../YoghurtGum/lib/Android/libstdc++.a
../../YoghurtGum/bin/YoghurtGum.a
-o bin/Galaxians.android
Line breaks are only for clarity, none exist in the actual output.
YoghurtGum is my game library that already statically and dynamically links to libstdc++.
When I remove lstdc++, the program doesn't compile because it can't find the library.
Is there a way to link to stdlibc++ statically or link the application to the correct dynamic library in the emulator?
Thanks in advance.
There is a modification of the ndk with support for exceptions, RTTI and stdlibc++.
http://www.crystax.net/android/ndk-r3.php
The other alternative involves porting just what you need, by hand... eek!