internal/build:support relocatable lib
This commit is contained in:
36
.github/workflows/llgo.yml
vendored
36
.github/workflows/llgo.yml
vendored
@@ -47,6 +47,27 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: llama2-model
|
name: llama2-model
|
||||||
path: ./_demo/llama2-c/
|
path: ./_demo/llama2-c/
|
||||||
|
- name: Download platform-specific demo libs
|
||||||
|
run: |
|
||||||
|
if ${{ startsWith(matrix.os, 'macos') }}; then
|
||||||
|
DEMO_PKG="cargs_darwin_arm64.zip"
|
||||||
|
else
|
||||||
|
DEMO_PKG="cargs_linux_amd64.zip"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p ./_demo/cargs/libs
|
||||||
|
cd ./_demo/cargs/libs
|
||||||
|
wget https://github.com/goplus/llpkg/releases/download/cargs/v1.0.0/${DEMO_PKG}
|
||||||
|
unzip ${DEMO_PKG}
|
||||||
|
|
||||||
|
# Process pc template files - replace {{.Prefix}} with actual path
|
||||||
|
ACTUAL_PREFIX="$(pwd)"
|
||||||
|
for tmpl in lib/pkgconfig/*.pc.tmpl; do
|
||||||
|
pc_file="${tmpl%.tmpl}"
|
||||||
|
sed "s|{{.Prefix}}|${ACTUAL_PREFIX}|g" "$tmpl" > "$pc_file"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "PKG_CONFIG_PATH=${ACTUAL_PREFIX}/lib/pkgconfig:${PKG_CONFIG_PATH}" >> $GITHUB_ENV
|
||||||
- name: Install further optional dependencies for demos
|
- name: Install further optional dependencies for demos
|
||||||
run: |
|
run: |
|
||||||
py_deps=(
|
py_deps=(
|
||||||
@@ -70,6 +91,18 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
go-version: ${{matrix.go}}
|
go-version: ${{matrix.go}}
|
||||||
|
|
||||||
|
- name: Test demo without RPATH (expect failure)
|
||||||
|
run: |
|
||||||
|
echo "Testing demo without RPATH (should fail)..."
|
||||||
|
export LLGO_FULL_RPATH=false
|
||||||
|
pkg-config --libs cargs
|
||||||
|
if (cd ./_demo/cargs && llgo run .); then
|
||||||
|
echo "ERROR: cargs demo should have failed without RPATH!"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "✓ cargs demo correctly failed without RPATH"
|
||||||
|
fi
|
||||||
|
|
||||||
- name: Test demos
|
- name: Test demos
|
||||||
run: |
|
run: |
|
||||||
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
# TODO(lijie): force python3-embed to be linked with python-3.12-embed
|
||||||
@@ -80,7 +113,8 @@ jobs:
|
|||||||
libdir=$(pkg-config --variable=libdir python-3.12-embed)
|
libdir=$(pkg-config --variable=libdir python-3.12-embed)
|
||||||
echo "libdir: $libdir"
|
echo "libdir: $libdir"
|
||||||
ln -s $libdir/pkgconfig/python-3.12-embed.pc $pcdir/python3-embed.pc
|
ln -s $libdir/pkgconfig/python-3.12-embed.pc $pcdir/python3-embed.pc
|
||||||
export PKG_CONFIG_PATH=$pcdir
|
export PKG_CONFIG_PATH=$pcdir:${PKG_CONFIG_PATH}
|
||||||
|
export LLGO_FULL_RPATH=true
|
||||||
bash .github/workflows/test_demo.sh
|
bash .github/workflows/test_demo.sh
|
||||||
|
|
||||||
- name: _xtool build tests
|
- name: _xtool build tests
|
||||||
|
|||||||
144
_demo/cargs/demo.go
Normal file
144
_demo/cargs/demo.go
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
_ "unsafe"
|
||||||
|
|
||||||
|
"github.com/goplus/lib/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
const LLGoPackage string = "link: $(pkg-config --libs cargs);"
|
||||||
|
|
||||||
|
type Option struct {
|
||||||
|
Identifier c.Char
|
||||||
|
AccessLetters *c.Char
|
||||||
|
AccessName *c.Char
|
||||||
|
ValueName *c.Char
|
||||||
|
Description *c.Char
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionContext struct {
|
||||||
|
Options *Option
|
||||||
|
OptionCount c.SizeT
|
||||||
|
Argc c.Int
|
||||||
|
Argv **c.Char
|
||||||
|
Index c.Int
|
||||||
|
InnerIndex c.Int
|
||||||
|
ErrorIndex c.Int
|
||||||
|
ErrorLetter c.Char
|
||||||
|
ForcedEnd bool
|
||||||
|
Identifier c.Char
|
||||||
|
Value *c.Char
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:type C
|
||||||
|
type Printer func(__llgo_arg_0 c.Pointer, __llgo_arg_1 *c.Char, __llgo_va_list ...interface{}) c.Int
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionInit C.cag_option_init
|
||||||
|
func (recv_ *OptionContext) OptionInit(options *Option, option_count c.SizeT, argc c.Int, argv **c.Char) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionFetch C.cag_option_fetch
|
||||||
|
func (recv_ *OptionContext) OptionFetch() bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGetIdentifier C.cag_option_get_identifier
|
||||||
|
func (recv_ *OptionContext) OptionGetIdentifier() c.Char {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGetValue C.cag_option_get_value
|
||||||
|
func (recv_ *OptionContext) OptionGetValue() *c.Char {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGetIndex C.cag_option_get_index
|
||||||
|
func (recv_ *OptionContext) OptionGetIndex() c.Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGetErrorIndex C.cag_option_get_error_index
|
||||||
|
func (recv_ *OptionContext) OptionGetErrorIndex() c.Int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGetErrorLetter C.cag_option_get_error_letter
|
||||||
|
func (recv_ *OptionContext) OptionGetErrorLetter() c.Char {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionPrintError C.cag_option_print_error
|
||||||
|
func (recv_ *OptionContext) OptionPrintError(destination *c.FILE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionPrinterError C.cag_option_printer_error
|
||||||
|
func (recv_ *OptionContext) OptionPrinterError(printer Printer, printer_ctx c.Pointer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*Option).OptionPrint C.cag_option_print
|
||||||
|
func (recv_ *Option) OptionPrint(option_count c.SizeT, destination *c.FILE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*Option).OptionPrinter C.cag_option_printer
|
||||||
|
func (recv_ *Option) OptionPrinter(option_count c.SizeT, printer Printer, printer_ctx c.Pointer) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionPrepare C.cag_option_prepare
|
||||||
|
func (recv_ *OptionContext) OptionPrepare(options *Option, option_count c.SizeT, argc c.Int, argv **c.Char) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// llgo:link (*OptionContext).OptionGet C.cag_option_get
|
||||||
|
func (recv_ *OptionContext) OptionGet() c.Char {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
options := []Option{
|
||||||
|
{
|
||||||
|
Identifier: 'h',
|
||||||
|
AccessLetters: c.Str("h"),
|
||||||
|
AccessName: c.Str("help"),
|
||||||
|
ValueName: nil,
|
||||||
|
Description: c.Str("Show help information"),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Identifier: 'v',
|
||||||
|
AccessLetters: c.Str("v"),
|
||||||
|
AccessName: c.Str("version"),
|
||||||
|
ValueName: nil,
|
||||||
|
Description: c.Str("Show version information"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
args := os.Args
|
||||||
|
|
||||||
|
// Convert Go string array to C-style argv
|
||||||
|
argv := make([]*int8, len(args))
|
||||||
|
for i, arg := range args {
|
||||||
|
argv[i] = c.AllocaCStr(arg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize option context
|
||||||
|
var context OptionContext
|
||||||
|
context.OptionInit(&options[0], uintptr(len(options)), c.Int(len(args)), &argv[0])
|
||||||
|
|
||||||
|
// Process all options
|
||||||
|
identifierFound := false
|
||||||
|
for context.OptionFetch() {
|
||||||
|
identifierFound = true
|
||||||
|
identifier := context.OptionGetIdentifier()
|
||||||
|
switch identifier {
|
||||||
|
case 'h':
|
||||||
|
fmt.Println("Help: This is a simple command-line parser demo")
|
||||||
|
case 'v':
|
||||||
|
fmt.Println("Version: 1.0.0")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default output if no identifier is found
|
||||||
|
if !identifierFound {
|
||||||
|
fmt.Println("Demo Command-line Tool\nIdentifier:\n\t-h: Help\n\t-v: Version")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -606,6 +606,19 @@ func linkMainPkg(ctx *context, pkg *packages.Package, pkgs []*aPackage, global l
|
|||||||
objFiles = append(objFiles, export)
|
objFiles = append(objFiles, export)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if IsFullRpathEnabled() {
|
||||||
|
exargs := make([]string, 0, ctx.nLibdir<<1)
|
||||||
|
// Treat every link-time library search path, specified by the -L parameter, as a runtime search path as well.
|
||||||
|
// This is to ensure the final executable can locate libraries with a relocatable install_name
|
||||||
|
// (e.g., "@rpath/libfoo.dylib") at runtime.
|
||||||
|
for _, arg := range linkArgs {
|
||||||
|
if strings.HasPrefix(arg, "-L") {
|
||||||
|
exargs = append(exargs, "-rpath", arg[2:])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
linkArgs = append(linkArgs, exargs...)
|
||||||
|
}
|
||||||
|
|
||||||
err = linkObjFiles(ctx, app, objFiles, linkArgs, verbose)
|
err = linkObjFiles(ctx, app, objFiles, linkArgs, verbose)
|
||||||
check(err)
|
check(err)
|
||||||
|
|
||||||
@@ -1002,6 +1015,7 @@ const llgoWasmRuntime = "LLGO_WASM_RUNTIME"
|
|||||||
const llgoWasiThreads = "LLGO_WASI_THREADS"
|
const llgoWasiThreads = "LLGO_WASI_THREADS"
|
||||||
const llgoStdioNobuf = "LLGO_STDIO_NOBUF"
|
const llgoStdioNobuf = "LLGO_STDIO_NOBUF"
|
||||||
const llgoCheckLinkArgs = "LLGO_CHECK_LINKARGS"
|
const llgoCheckLinkArgs = "LLGO_CHECK_LINKARGS"
|
||||||
|
const llgoFullRpath = "LLGO_FULL_RPATH"
|
||||||
|
|
||||||
const defaultWasmRuntime = "wasmtime"
|
const defaultWasmRuntime = "wasmtime"
|
||||||
|
|
||||||
@@ -1053,6 +1067,10 @@ func IsCheckLinkArgsEnabled() bool {
|
|||||||
return isEnvOn(llgoCheckLinkArgs, false)
|
return isEnvOn(llgoCheckLinkArgs, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsFullRpathEnabled() bool {
|
||||||
|
return isEnvOn(llgoFullRpath, true)
|
||||||
|
}
|
||||||
|
|
||||||
func WasmRuntime() string {
|
func WasmRuntime() string {
|
||||||
return defaultEnv(llgoWasmRuntime, defaultWasmRuntime)
|
return defaultEnv(llgoWasmRuntime, defaultWasmRuntime)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user