Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion .github/workflows/llgo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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=(
Expand All @@ -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
Expand All @@ -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
Expand Down
144 changes: 144 additions & 0 deletions _demo/cargs/demo.go
Original file line number Diff line number Diff line change
@@ -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")
}
}
18 changes: 18 additions & 0 deletions internal/build/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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"

Expand Down Expand Up @@ -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)
}
Expand Down
Loading