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:
|
||||
name: llama2-model
|
||||
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
|
||||
run: |
|
||||
py_deps=(
|
||||
@@ -70,6 +91,18 @@ jobs:
|
||||
with:
|
||||
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
|
||||
run: |
|
||||
# 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)
|
||||
echo "libdir: $libdir"
|
||||
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
|
||||
|
||||
- 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)
|
||||
}
|
||||
|
||||
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)
|
||||
check(err)
|
||||
|
||||
@@ -1002,6 +1015,7 @@ const llgoWasmRuntime = "LLGO_WASM_RUNTIME"
|
||||
const llgoWasiThreads = "LLGO_WASI_THREADS"
|
||||
const llgoStdioNobuf = "LLGO_STDIO_NOBUF"
|
||||
const llgoCheckLinkArgs = "LLGO_CHECK_LINKARGS"
|
||||
const llgoFullRpath = "LLGO_FULL_RPATH"
|
||||
|
||||
const defaultWasmRuntime = "wasmtime"
|
||||
|
||||
@@ -1053,6 +1067,10 @@ func IsCheckLinkArgsEnabled() bool {
|
||||
return isEnvOn(llgoCheckLinkArgs, false)
|
||||
}
|
||||
|
||||
func IsFullRpathEnabled() bool {
|
||||
return isEnvOn(llgoFullRpath, true)
|
||||
}
|
||||
|
||||
func WasmRuntime() string {
|
||||
return defaultEnv(llgoWasmRuntime, defaultWasmRuntime)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user