使用Golang写C的动态库,当前项目目录root@working-srv: tree ././|-- hello| `-- main.go`-- main.c.root@working-srv: more hello/main.go package mainimport "C"func main() {}//export Hellofunc Hello() string { return "Hello"}//export Testfunc Test() { println("export Test")}项目目录root@working-srv:/data/code/src# tree project workspace/project└── pro.goworkspace/└── main.go.
[leconte@localhost demolib]$ sconsscons: Reading SConscript files ...gcc -o a.o -c a.cgcc -o b.o -c b.cgcc -o main.o -c main.car rc libdemo.a a.o b.oranlib libdemo.agcc -o demo main.o -L. -ldemoscons: done building targets.[leconte@localhost demolib]$ cat SConstructSConscript([''test1/SConscript'', ''test2/SConscript'', ''test3/SConscript'', ''test4/SConscript''])
lib.go 源文件。package mainimport "C"//export Hellofunc Hello() string { return "Hello"}func main() {}生成GO动态库。将这段代码生成GO动态库,进入该源码目录执行:go install -v -x -buildmode=shared runtime sync/atomic #构建核心基本库go install -v -x -buildmode=shared -linkshared #构建GO动态库调用。D:\tmp\go15>go build -v -x -buildmode=shared-buildmode=shared not supported on windows/386.
Linux下GCC编程四个过程在Linux下进行C语言编程,必然要采用GNU GCC来编译C源代码生成可执行程序。hello.c hello.i hello.o hello.s.hello.c hello.exe hello.i hello.o hello.s.最后的答案是:系统把这些函数实现都被做到名为libc.so.6的库文件中去了,在没有特别指定时,gcc会到系统默认的搜索路径"/usr/lib"下进行查找,也就是链接到libc.so.6库函数中去,这样就能实现函数"printf" 了,而这也就是链接的作用。
如何用gcc编译生成动态链接库*.so文件 转:如何编译.so动态库 问:我源文件为main.c, x.c, y.c, z.c,头文件为x.h,y.h,z.h如何编译成.so动态库?# 输出LD_LIBRARY_PATH环境变量,一边动态库装载器能够找到需要的动态库export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.这里有一个头文件:so_test.h,三个.c文件:test_a.c、test_b.c、test_c.c,我们将这几个文件编译成一个动态库:libtest.so。$ gcc test.c -L. -ltest -o test.
相对GOPATH/src路径。goWorkSpace // goWorkSpace为GOPATH目录 -- bin -- myApp1 // 编译生成 -- myApp2 // 编译生成 -- myApp3 // 编译生成 -- pkg -- src -- common 1 -- common 2 -- common utils ...-- myApp1 // project1 -- models -- controllers -- others -- main.go -- myApp2 // project2 -- models -- controllers -- others -- main.go -- myApp3 // project3 -- models -- controllers -- others -- main.go.
4,Go程序中指定 CFLAGS 和 LDFLAGS#cgo CFLAGS: -I ./include #cgo LDFLAGS: -L .b -lhello -Wl,-rpath,/usr/localb.package main /* #cgo CFLAGS: -I ./include #cgo LDFLAGS: -L ./lib -lhello #include "hello.h" */ import "C" func main() { C.hello(C.CString("call C hello func")) }#include "hello.h"#include <stdio.h>void hello(const char *str){ printf("%s(%d): %s\n", __FUNCTION__, __LINE__, str);
这就是 Go 程序的入口地址,我是在 linux 上运行的,所以入口文件为 src/runtime/rt0_linux_amd64.s,runtime 目录下有各种不同名称的程序入口文件,支持各种操作系统和架构,代码为:例如 main 包里引用的 fmt 的源码路径是 /usr/local/go/src/fmt,而 util 的源码路径是 /Users/qcrao/hello-world/src/util,正好我们设置的 GoPath = /Users/qcrao/hello-world。【Go 编译命令执行过程】https://halfrost.com/go_command/
Golang Go语言简单的文件服务器。package main.import “http”func main(){h := http.FileServer(http.Dir(“/Users/skey/Sites”))http.ListenAndServe(“:8080″, h)}
Go语言实践技巧(15)——禁止编译优化。
谈谈 Golang 中的 Data RaceAny race is a bug.当通过 go run-race cmd.go 执行时,可以看到有明显的竞态出现:有些朋友可能不知道,在 Go(甚至是大部分语言)中,一条普通的赋值语句其实并不是一个原子操作(语言规范同样没有定义 i++ 是原子操作, 任何变量的赋值都不是原子操作)。其实就是利用 atomic 特性,那 atomic 会比 mutex 有什么好处呢?mutex 由操作系统实现,而 atomic 包中的原子操作则由底层硬件直接提供支持。
/usr/bin/env gorun 3 @author :xxxx 4 Blog:http://www.cnblogs.com/xxxx/tag/GO%E8%AF%AD%E8%A8%80%E7%9A%84%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 5 EMAIL:xxxx@qq.com 6 */ 7 8 '''''''''''''''''''''''' 9 [root@xxxx day3]# more str_note.go 10 package main11 12 import (13 "fmt"14 )15 16 func main() {17 str1 := "xxxx\thave a apple!" //"\t"表示制表符,会根据操作系统自动空出几个空格。
解决因SDL同时使用静态库和动态库出现的编译问题在包含 的文件下面添加:#ifdef main#undef main#endif在自己的main函数中添加:if( SDL_Init(SDL_INIT_NOPARACHUTE) <0 ){return(FALSE);}SDL_SetModuleHandle(GetModuleHandle(NULL));原因分析:编译时 运行库使用MTD 由于SDL同时使用静态库和动态库 所以链接会出错。
package mainimport ( "plugin")func main() { //加载动态库 p, err := plugin.Open("plugin.so") if err != nil { panic(err) } //查找函数 f, err := p.Lookup("DCall") if err != nil { panic(err) } //转换类型后调用函数 f.(func())() f2, err := p.Lookup("DCallWithParam") if err != nil { panic(err) } //带参函数的调用 f2.(func(string))("hello world,plugin.so")}
[stevenrao]$ g++ -shared -o libtmp.so tmp.o.[stevenrao]$ g++ -o demo -L/tmp -ltmp main.cpp。前面链接时候使用 -L/tmp/ -ltmp 是一种设置相对路径方法,还有一种绝对路径链接方法。[stevenrao]$ g++ -o demo /tmp/libtmp.so main.cpp。像前面提到的 -L/tmp/ 是属于链接时期的搜索路径,即给ld程序提供的编译链接时候寻找动态库路径;而 LD_LIBRARY_PATH则既属于链接期搜索路径,又属于运行时期的搜索路径。
⑴编写函数代码⑵编译生成各目标文件⑶用ar文件对目标文件归档,生成静态库文件。具体的调用方式会在 "五、动态库的调用" 中周详说明.2、编写最简单的动态库文件 为了便于对照, 我们仍然采用静态库中的文件做例子. 编写如下两个文件,注意放在同一目录中 myalib.h //静态库头文件 myalib.c //静态库实现文件 //myalib.h 文件的内容void test(); //myalib.c 文件的内容#inlcude void test(){
静态库和动态库Linux中有两类函数库,分别是静态库和动态库。这类库的名字一般是libxxx.so;相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。下面来介绍linux静态函数库的创建和使用:此时还不能立即./out,因为在动态函数库使用时,会查找/usr/lib /lib目录下的动态函数库,而此时我们生成的库不在里边。
总结:上面这是最“原始"的方式连链接静态库和动态库,即把库文件作为gcc的输入文件,规则当然和源文件和目标文件类似了,不管是使用相对路径还是绝对路径,总之是必须能让gcc直接找到的。对于这种方式,使用-L或者把libtest1.so复制到/lib、/usr/lib这些方式,都不能简化为"gcc main.cpp libtest1.so”(当然是libtest1.so不在当前目录的情况下)。
GCC编译器(2)4、警告选项。在编译过程中,编译器的报错和警告信息对于程序员来说是非常重要的信息,GCC包含完整的出错检查和警告提示功能,它可以帮助Linux程序员尽快找出错误的或潜在的错误代码,从而写过更优美的代码。$ gcc -Wparentheses example5.c -o example5.函数的具体实现实在库文件中完成的,库文件可分为静态库和动态库,静态库是指编译连接时,将库文件的代码全部加入到可执行文件中,这样运行时就不需要库文件了。
Linux下g++编译与使用静态库和动态库。linux下用生成静态库的命令 ar 处理 myAPI.o 文件生成静态库文件,生成的库文件应遵循规范,及linux下库文件加“lib”前缀。[plain] view plaincopyar crv libmyAPI.a myAPI.o 接下来即可在项目编译过程中利用静态库了,此时 myAPI.cpp 这个库函数的定义文件已经不需要了。main.cpp 编译命令如下(注意,依赖的静态库文件要放在被依赖项后面):
源文件----预处理---->预处理文件(*.i)----编译---->汇编文件(*.s)----汇编编译---->目标文件(*.o)----链接---->可执行文件。-c 编译,汇编源文件,不链接,得到*.o文件-S 只编译,不汇编,得到*.s文件-E 预处理文件,得到*.E文件-o [dis] [src] 将src文件编译成可执行文件dis-Idir 指定include包含文件搜索路径-g 生成具有调试信息,如果不加这个选项,*.o文件中不会生成.debug段,在调试时将不能查看打印变量值。
Android Studio中NDK开发使用预编译好的.so动态库 Menu.之前有人问到怎么使用Android Studio进行NDK开发,经过网上搜索,自己也尝试了一下,用Android Studio进行NDK开发比Eclipse更加灵活方便。在ADT中进行NDK开发非常简单,在Android Studio进行NDK开发也同样的容易。dir=/path/to/android-sdk ndk.Android NDK开发(五)——C代码回调Java代码 记得以前面试的时候被问到JNI中Native代码怎么回调Java代码,本文有比较详尽的解答。
[hongfuhao@localhost src]$ lsADD.c fun.h makefile MUL.c SUB.c[hongfuhao@localhost src]$ gcc -c *.c[hongfuhao@localhost src]$ lsADD.c ADD.o fun.h makefile MUL.c MUL.o SUB.c SUB.o[hongfuhao@localhost src]$ ar -cr libfun.a *.o[hongfuhao@localhost src]$ lsADD.c ADD.o fun.h libfun.a makefile MUL.c MUL.o SUB.c SUB.o.[hongfuhao@localhost app]$ lsAPP main.c makefile.
├── hello.c├── hello.h├── libhello.so -> libhello.so.0.0.1├── libhello.so.0 -> libhello.so.0.0.1├── libhello.so.0.0.1└── main.c.其实在生成main程序的过程有如下几步链接器通过编译命令-L. -lhello在当前目录查找libhello.so文件读取libhello.so链接指向的实际文件,这里是libhello.so.0.0.1读取libhello.so.0.0.1中的SONAME,这里是libhello.so.0将libhello.so.0记录到main程序的二进制数据里。
#include <stdio.h>extern void print_num();print_num.c.#include <stdio.h>extern int g_num;void print_num(){ ++ g_num;printf("g_num=%d\n", g_num);gcc -o libprint_num.so -shared -fPIC print_num.cgcc -o t1 t1.c -ldl -L. -lprint_num.#include <dlfcn.h>#include <stdio.h>int g_num = 0;void *h = dlopen("./libprint_num.so", RTLD_NOW);} Func f = (Func)dlsym(h, "print_num");--t2--./libprint_num.
golang Go 删除文件。
//清除错误信息 pf_t pf=(pf_t)dlsym(handle,argv[1] ); //找到指定函数的指针 if ((error = dlerror()) != NULL) { fprintf (stderr, "%s\n", error); exit(1); } pf(10,2); dlclose(handle); //关闭调用动态库句柄 return 0;}我在测试的时候,只是使用了add函数和sub函数。加载 add.so 动态库, 并调用 add 函数,
package mainimport ( "fmt" "test/goemail/libofm")func main() { mycontent := " my dear令" email := libofm.NewEmail("xxxxx@qq.com;xxxxxx@qq.com;", "test golang email", mycontent) err := libofm.SendEmail(email) fmt.Println(err)}