使用cgo、LuaJIT和musl构建静态二进制文件。

huangapple go评论113阅读模式
英文:

Build static binary with cgo, LuaJIT and musl

问题

阅读完《Statically compiled Go programs, always, even with cgo, using musl》之后,我尝试使用描述的方法来静态链接LuaJIT。

  • 使用https://github.com/aarzilli/golua的Go绑定
  • 假设muslgolua已经安装

我尝试构建的Go代码:

package main

import "github.com/aarzilli/golua/lua"
import "fmt"

func test(L *lua.State) int {
    fmt.Println("hello world! from go!")
    return 0
}

func test2(L *lua.State) int {
    arg := L.CheckInteger(-1)
    argfrombottom := L.CheckInteger(1)
    fmt.Print("test2 arg:")
    fmt.Println(arg)
    fmt.Print("from bottom:")
    fmt.Println(argfrombottom)
    return 0
}

func main() {
    L := lua.NewState()
    defer L.Close()
    L.OpenLibs()

    L.GetField(lua.LUA_GLOBALSINDEX, "print")
    L.PushString("Hello World!")
    L.Call(1, 0)

    L.PushGoFunction(test)
    L.PushGoFunction(test)
    L.PushGoFunction(test)
    L.PushGoFunction(test)

    L.PushGoFunction(test2)
    L.PushInteger(42)
    L.Call(1, 0)

    L.Call(0, 0)
    L.Call(0, 0)
    L.Call(0, 0)

    // this will fail as we didn't register test2 function
    err := L.DoString("test2(42)")

    fmt.Printf("Ciao %v\n", err)
}

使用参数和输出的构建命令:

$ CC="/usr/local/musl/bin/musl-gcc" go build --ldflags '-linkmode external -extldflags "-static"' basic.go
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running /usr/local/musl/bin/musl-gcc failed: exit status 1
/usr/bin/ld: cannot find -lluajit-5.1
collect2: error: ld returned 1 exit status

使用LD_DEBUG=all可以获得更多信息(8000+行)。

我的问题是:问题出在哪里,如何解决?我认为这里可能有一些提示,但我无法完全理解。

我采取了以下步骤:

1. 使用musl构建静态LuaJIT库。

$ make STATIC_CC="/usr/local/musl/bin/musl-gcc" CCOPT="-static -fPIC" BUILDMODE="static"
...
==== Successfully built LuaJIT 2.0.4 ====

2. 使用musl构建动态LuaJIT库。

$ make DYNAMIC_CC="/usr/local/musl/bin/musl-gcc" BUILDMODE="dynamic"
...
==== Successfully built LuaJIT 2.0.4 ====

3. 检查构建结果。

$ find . -iname *.a -o -iname *.so
./src/libluajit.a
./src/libluajit.so

4. 安装LuaJIT。

$ sudo make install
...
==== Successfully installed LuaJIT 2.0.4 to /usr/local ====

5. 检查安装结果。

$ pkg-config luajit --cflags
-I/usr/include/luajit-2.0
$ pkg-config luajit --libs
-lluajit-5.1

6. 修改golua的lua.go文件以使用硬编码的cgo参数。

我在覆盖这些值时遇到了问题,所以我只是修改了源代码。

旧的带有cgo参数的C注释:

/*
#cgo CFLAGS: -I ${SRCDIR}/lua
#cgo llua LDFLAGS: -llua
#cgo luaa LDFLAGS: -llua -lm -ldl
#cgo linux,!llua,!luaa LDFLAGS: -llua5.1
#cgo darwin,!luaa pkg-config: lua5.1
#cgo freebsd,!luaa LDFLAGS: -llua-5.1
#cgo windows,!llua LDFLAGS: -L${SRCDIR} -llua -lmingwex -lmingw32
#include <lua.h>
#include <stdlib.h>
#include "golua.h"
*/
import "C"

新的:

/*
#cgo CFLAGS: -I/usr/include/luajit-2.0 -I${SRCDIR}/lua
#cgo LDFLAGS: -lluajit-5.1
#include <lua.h>
#include <stdlib.h>
#include "golua.h"
*/
import "C"

7. 构建一些示例

如问题开头所示。

LuaJIT的安装位置:

$ find / -iname libluajit* 2> /dev/null
/usr/local/lib/libluajit-5.1.so.2
/usr/local/lib/libluajit-5.1.a
/usr/local/lib/libluajit-5.1.so
/usr/local/lib/libluajit-5.1.so.2.0.4
/usr/lib/libluajit-5.1.so.2.0.5
/usr/lib/libluajit-5.1.so.2
/usr/lib/libluajit-5.1.a
/usr/lib/libluajit-5.1.so
/usr/lib/libluajit.s

编辑 1

我按照@putu的评论更改了#cgo LDFLAGS

#cgo LDFLAGS: -L/usr/local/lib -lluajit-5.1

现在我有

$ CC="/usr/local/musl/bin/musl-gcc" go build --ldflags '-linkmode external -extldflags "-static -fPIC"' basic.go
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running /usr/local/musl/bin/musl-gcc failed: exit status 1
/tmp/go-link-916770907/000000.o: In function `printf':
/usr/include/x86_64-linux-gnu/bits/stdio2.h:104: undefined reference to `__printf_chk'
collect2: error: ld returned 1 exit status
英文:

After reading Statically compiled Go programs, always, even with cgo, using musl I'm trying to use described method to statically link LuaJIT.

Go code I try to build:

package main

import &quot;github.com/aarzilli/golua/lua&quot;
import &quot;fmt&quot;

func test(L *lua.State) int {
    fmt.Println(&quot;hello world! from go!&quot;)
    return 0
}

func test2(L *lua.State) int {
    arg := L.CheckInteger(-1)
    argfrombottom := L.CheckInteger(1)
    fmt.Print(&quot;test2 arg: &quot;)
    fmt.Println(arg)
    fmt.Print(&quot;from bottom: &quot;)
    fmt.Println(argfrombottom)
    return 0
}

func main() {
    L := lua.NewState()
    defer L.Close()
    L.OpenLibs()

    L.GetField(lua.LUA_GLOBALSINDEX, &quot;print&quot;)
    L.PushString(&quot;Hello World!&quot;)
    L.Call(1, 0)

    L.PushGoFunction(test)
    L.PushGoFunction(test)
    L.PushGoFunction(test)
    L.PushGoFunction(test)

    L.PushGoFunction(test2)
    L.PushInteger(42)
    L.Call(1, 0)

    L.Call(0, 0)
    L.Call(0, 0)
    L.Call(0, 0)

    // this will fail as we didn&#39;t register test2 function
    err := L.DoString(&quot;test2(42)&quot;)

    fmt.Printf(&quot;Ciao %v\n&quot;, err)
}

Build command with parameters and output:

$ CC=&quot;/usr/local/musl/bin/musl-gcc&quot; go build --ldflags &#39;-linkmode external -extldflags &quot;-static&quot;&#39; basic.go
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running /usr/local/musl/bin/musl-gcc failed: exit status 1
/usr/bin/ld: cannot find -lluajit-5.1
collect2: error: ld returned 1 exit status

Using LD_DEBUG=all I can get more information (8000+ lines).

My question: what is the problem and how to solve it? I think there can be some hint here but I can't quite grasp it.

I took following steps:

1. Build static LuaJIT library with musl.

$ make STATIC_CC=&quot;/usr/local/musl/bin/musl-gcc&quot; CCOPT=&quot;-static -fPIC&quot; BUILDMODE=&quot;static&quot;
...
==== Successfully built LuaJIT 2.0.4 ====

2. Build dynamic LuaJIT library with musl.

$ make DYNAMIC_CC=&quot;/usr/local/musl/bin/musl-gcc&quot; BUILDMODE=&quot;dynamic&quot;
...
==== Successfully built LuaJIT 2.0.4 ====

3. Check build.

$ find . -iname *.a -o -iname *.so
./src/libluajit.a
./src/libluajit.so

4. Install it.

$ sudo make install
...
==== Successfully installed LuaJIT 2.0.4 to /usr/local ====

5. Check installation.

$ pkg-config luajit --cflags
-I/usr/include/luajit-2.0
$ pkg-config luajit --libs
-lluajit-5.1

6. Modify golua lua.go file to use hardcoded cgo parameters.

I had problems overriding those values so I simply modify source code.

old C comment with cgo parameters:

/*
#cgo CFLAGS: -I ${SRCDIR}/lua
#cgo llua LDFLAGS: -llua
#cgo luaa LDFLAGS: -llua -lm -ldl
#cgo linux,!llua,!luaa LDFLAGS: -llua5.1
#cgo darwin,!luaa pkg-config: lua5.1
#cgo freebsd,!luaa LDFLAGS: -llua-5.1
#cgo windows,!llua LDFLAGS: -L${SRCDIR} -llua -lmingwex -lmingw32
#include &lt;lua.h&gt;
#include &lt;stdlib.h&gt;
#include &quot;golua.h&quot;
*/
import &quot;C&quot;

new:

/*
#cgo CFLAGS: -I/usr/include/luajit-2.0 -I${SRCDIR}/lua
#cgo LDFLAGS: -lluajit-5.1
#include &lt;lua.h&gt;
#include &lt;stdlib.h&gt;
#include &quot;golua.h&quot;
*/
import &quot;C&quot;

7. Build some example

As shown at the beggining of question.

Where LuaJIT got installed:

$ find / -iname libluajit* 2&gt; /dev/null
/usr/local/lib/libluajit-5.1.so.2
/usr/local/lib/libluajit-5.1.a
/usr/local/lib/libluajit-5.1.so
/usr/local/lib/libluajit-5.1.so.2.0.4
/usr/lib/libluajit-5.1.so.2.0.5
/usr/lib/libluajit-5.1.so.2
/usr/lib/libluajit-5.1.a
/usr/lib/libluajit-5.1.so
/usr/lib/libluajit.s

EDIT 1

I've followed @putu's comment and changed #cgo LDFLAGS to

#cgo LDFLAGS: -L/usr/local/lib -lluajit-5.1

now I have

$ CC=&quot;/usr/local/musl/bin/musl-gcc&quot; go build --ldflags &#39;-linkmode external -extldflags &quot;-static -fPIC&quot;&#39; basic.go
# command-line-arguments
/usr/local/go/pkg/tool/linux_amd64/link: running /usr/local/musl/bin/musl-gcc failed: exit status 1
/tmp/go-link-916770907/000000.o: In function `printf&#39;:
/usr/include/x86_64-linux-gnu/bits/stdio2.h:104: undefined reference to `__printf_chk&#39;
collect2: error: ld returned 1 exit status

1: https://dominik.honnef.co/posts/2015/06/go-musl/ "Statically compiled Go programs, always, even with cgo, using musl"
2: http://luajit.org/ "LuaJIT"
3: https://www.musl-libc.org/ "musl"
4: https://github.com/aarzilli/golua "golua"
5: https://gist.github.com/anonymous/776297075dcc080a20ffe435902f3f57 "more information"
6: https://stackoverflow.com/questions/38785691/trying-to-build-static-cgo-executable-with-oracle-libraries-on-linux-ubuntu "here"
7: https://stackoverflow.com/users/6207052/ "putu"

答案1

得分: 0

@putu指导我朝着正确的方向前进,我所需要做的就是调整CFLAGS以包含musl

lua.go中清理了C注释:

/*
#cgo CFLAGS: -I/usr/include/luajit-2.0 -I/usr/local/musl/include/
#cgo LDFLAGS: -L/usr/local/lib -lluajit-5.1
#include <lua.h>
#include <stdlib.h>
#include "golua.h"
*/
import "C"

看起来一切都构建得很好:

$ CC="/usr/local/musl/bin/musl-gcc" go build --ldflags '-linkmode external -extldflags "-static"' basic.go
$ file basic
basic: ELF 64-bit LSB可执行文件,x86-64,版本1(SYSV),静态链接,未剥离
$ ./basic 
Hello World!
test2 arg: 42
from bottom: 42
hello world! from go!
hello world! from go!
hello world! from go!
Ciao [string "test2(42)"]:1: 尝试调用全局变量'test2'(一个空值)
英文:

@putu pointed me to the right direction, all I had to do was tune CFLAGS to include musl.

Cleaned up C comment in lua.go:

/*
#cgo CFLAGS: -I/usr/include/luajit-2.0 -I/usr/local/musl/include/
#cgo LDFLAGS: -L/usr/local/lib -lluajit-5.1
#include &lt;lua.h&gt;
#include &lt;stdlib.h&gt;
#include &quot;golua.h&quot;
*/
import &quot;C&quot;

Looks like everything builds just fine:

$ CC=&quot;/usr/local/musl/bin/musl-gcc&quot; go build --ldflags &#39;-linkmode external -extldflags &quot;-static&quot;&#39; basic.go
$ file basic
basic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
$ ./basic 
Hello World!
test2 arg: 42
from bottom: 42
hello world! from go!
hello world! from go!
hello world! from go!
Ciao [string &quot;test2(42)&quot;]:1: attempt to call global &#39;test2&#39; (a nil value)

1: https://stackoverflow.com/users/6207052/ "@putu"

huangapple
  • 本文由 发表于 2017年6月5日 04:02:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/44358275.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定