Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

llcppg:linux adapt #160

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
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
13 changes: 13 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,19 @@ jobs:

llcppgtest -demos ./_llcppgtest

- name: Test demos with generated pkgs
if: startsWith(matrix.os, 'ubuntu')
run: |
# install demo's lib
sudo apt install liblua5.4-dev libsqlite3-dev libgmp-dev libgpg-error-dev zlib1g-dev -y
llcppgtest -demo ./_llcppgtest/cjson
llcppgtest -demo ./_llcppgtest/lua
llcppgtest -demo ./_llcppgtest/sqlite
llcppgtest -demo ./_llcppgtest/gmp
llcppgtest -demo ./_llcppgtest/gpgerror
llcppgtest -demo ./_llcppgtest/zlib


- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v5
with:
Expand Down
4 changes: 2 additions & 2 deletions _llcppgtest/cjson/llcppg.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"cflags": "$(pkg-config --cflags libcjson)",
"libs": "$(pkg-config --libs libcjson libcjson_utils)",
"include": [
"cjson/cJSON.h",
"cjson/cJSON_Utils.h"
"cJSON.h",
"cJSON_Utils.h"
],
"trimPrefixes": ["cJSON_", "cJSONUtils_"],
"cplusplus": false
Expand Down
3 changes: 2 additions & 1 deletion _xtool/llcppsigfetch/llcppsigfetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/goplus/llcppg/_xtool/llcppsymg/clangutils"
"github.com/goplus/llcppg/_xtool/llcppsymg/config"
"github.com/goplus/llcppg/_xtool/llcppsymg/config/cfgparse"
"github.com/goplus/llcppg/_xtool/llcppsymg/syspath"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/cjson"
)
Expand Down Expand Up @@ -154,7 +155,7 @@ func runFromConfig(cfgFile string, useStdin bool, outputToFile bool, verbose boo
}

cflag := cfgparse.ParseCFlags(conf.CFlags)
files, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
files, notFounds, err := cflag.GenHeaderFilePaths(conf.Include, syspath.GetIncludePaths())
check(err)

if verbose {
Expand Down
2 changes: 1 addition & 1 deletion _xtool/llcppsymg/_cmptest/config_test/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func TestGenHeaderFilePath() {
fmt.Printf("Input files: %v\n", tc.files)

cflag := cfgparse.ParseCFlags(tc.cflags)
result, notFounds, err := cflag.GenHeaderFilePaths(tc.files)
result, notFounds, err := cflag.GenHeaderFilePaths(tc.files, []string{})

if err != nil {
fmt.Printf("Error: %v\n", err)
Expand Down
9 changes: 9 additions & 0 deletions _xtool/llcppsymg/_cmptest/syspath_test/llgo.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#stdout
=== TestLdOutput ===
[/usr/local/lib/aarch64-linux-gnu /lib/aarch64-linux-gnu /usr/lib/aarch64-linux-gnu /usr/local/lib /lib /usr/lib /usr/aarch64-linux-gnu/lib]
=== TestClangIncOutput ===
[/usr/lib/llvm-18/lib/clang/18/include /usr/local/include /usr/include/aarch64-linux-gnu /usr/include]

#stderr

#exit 0
89 changes: 89 additions & 0 deletions _xtool/llcppsymg/_cmptest/syspath_test/syspath.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package main

import (
"fmt"

"github.com/goplus/llcppg/_xtool/llcppsymg/syspath"
)

func main() {
TestLdOutput()
TestClangIncOutput()
}

func TestLdOutput() {
fmt.Println("=== TestLdOutput ===")
res := syspath.ParseLdOutput(
`GNU ld (GNU Binutils for Ubuntu) 2.42
Supported emulations:
aarch64linux
aarch64elf
aarch64elf32
aarch64elf32b
aarch64elfb
armelf
armelfb
aarch64linuxb
aarch64linux32
aarch64linux32b
armelfb_linux_eabi
armelf_linux_eabi
using internal linker script:
==================================================
/* Script for -z combreloc */
/* Copyright (C) 2014-2024 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64",
"elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/aarch64-linux-gnu"); SEARCH_DIR("=/lib/aarch64-linux-gnu"); SEARCH_DIR("=/usr/lib/aarch64-linux-gnu"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/aarch64-linux-gnu/lib");
SECTIONS
{
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
`)
fmt.Println(res)
}

func TestClangIncOutput() {
fmt.Println("=== TestClangIncOutput ===")
res := syspath.ParseClangIncOutput(
`Ubuntu clang version 18.1.3 (1ubuntu1)
Target: aarch64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
Found candidate GCC installation: /usr/bin/../lib/gcc/aarch64-linux-gnu/13
Selected GCC installation: /usr/bin/../lib/gcc/aarch64-linux-gnu/13
Candidate multilib: .;@m64
Selected multilib: .;@m64
(in-process)
"/usr/lib/llvm-18/bin/clang" -cc1 -triple aarch64-unknown-linux-gnu -E -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name null -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=non-leaf -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu generic -target-feature +v8a -target-feature +fp-armv8 -target-feature +neon -target-abi aapcs -debugger-tuning=gdb -fdebug-compilation-dir=/root/llcppg -v -fcoverage-compilation-dir=/root/llcppg -resource-dir /usr/lib/llvm-18/lib/clang/18 -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include -internal-externc-isystem /usr/include/aarch64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fno-signed-char -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fcolor-diagnostics -target-feature +outline-atomics -target-feature -fmv -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o - -x c /dev/null
clang -cc1 version 18.1.3 based upon LLVM 18.1.3 default target aarch64-unknown-linux-gnu
ignoring nonexistent directory "/usr/bin/../lib/gcc/aarch64-linux-gnu/13/../../../../aarch64-linux-gnu/include"
ignoring nonexistent directory "/include"
#include "..." search starts here:
#include <...> search starts here:
/usr/lib/llvm-18/lib/clang/18/include
/usr/local/include
/usr/include/aarch64-linux-gnu
/usr/include
End of search list.
# 1 "/dev/null"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
# 399 "<built-in>" 3
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "/dev/null" 2
`)
fmt.Println(res)
}
6 changes: 4 additions & 2 deletions _xtool/llcppsymg/config/cfgparse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,15 @@ func ParseCFlags(cflags string) *CFlags {
return cf
}

func (cf *CFlags) GenHeaderFilePaths(files []string) ([]string, []string, error) {
func (cf *CFlags) GenHeaderFilePaths(files []string, defaultPaths []string) ([]string, []string, error) {
var foundPaths []string
var notFound []string

searchPaths := append(cf.Paths, defaultPaths...)

for _, file := range files {
var found bool
for _, path := range cf.Paths {
for _, path := range searchPaths {
fullPath := filepath.Join(path, file)
if _, err := os.Stat(fullPath); err == nil {
foundPaths = append(foundPaths, fullPath)
Expand Down
7 changes: 6 additions & 1 deletion _xtool/llcppsymg/llcppsymg.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/goplus/llcppg/_xtool/llcppsymg/dbg"
"github.com/goplus/llcppg/_xtool/llcppsymg/parse"
"github.com/goplus/llcppg/_xtool/llcppsymg/symbol"
"github.com/goplus/llcppg/_xtool/llcppsymg/syspath"
)

func main() {
Expand Down Expand Up @@ -79,7 +80,11 @@ func main() {
check(err)

cflag := cfgparse.ParseCFlags(conf.CFlags)
filepaths, notFounds, err := cflag.GenHeaderFilePaths(conf.Include)
syspaths := syspath.GetIncludePaths()
if ags.Verbose {
fmt.Println("syspaths", syspaths)
}
filepaths, notFounds, err := cflag.GenHeaderFilePaths(conf.Include, syspaths)
check(err)

if ags.Verbose {
Expand Down
69 changes: 12 additions & 57 deletions _xtool/llcppsymg/symbol/symbol.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/goplus/llcppg/_xtool/llcppsymg/config/cfgparse"
"github.com/goplus/llcppg/_xtool/llcppsymg/dbg"
"github.com/goplus/llcppg/_xtool/llcppsymg/parse"
"github.com/goplus/llcppg/_xtool/llcppsymg/syspath"
"github.com/goplus/llcppg/types"
"github.com/goplus/llgo/c"
"github.com/goplus/llgo/c/cjson"
Expand All @@ -28,7 +29,11 @@ func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) {
if dbg.GetDebugSymbol() {
fmt.Println("ParseDylibSymbols:from", lib)
}
sysPaths := getSysLibPaths()
sysPaths := syspath.GetLibPaths()
if dbg.GetDebugSymbol() {
fmt.Println("ParseDylibSymbols:sysPaths", sysPaths)
}

lbs := cfgparse.ParseLibs(lib)
if dbg.GetDebugSymbol() {
fmt.Println("ParseDylibSymbols:LibConfig Parse To")
Expand Down Expand Up @@ -60,7 +65,12 @@ func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) {
continue
}

files, err := nm.New("").List(dylibPath)
args := []string{}
if runtime.GOOS == "linux" {
args = append(args, "-D")
}

files, err := nm.New("").List(dylibPath, args...)
if err != nil {
parseErrors = append(parseErrors, fmt.Sprintf("ParseDylibSymbols:Failed to list symbols in dylib %s: %v", dylibPath, err))
continue
Expand All @@ -84,61 +94,6 @@ func ParseDylibSymbols(lib string) ([]*nm.Symbol, error) {
return nil, fmt.Errorf("no symbols found in any dylib. Errors: %v", parseErrors)
}

func getSysLibPaths() []string {
var paths []string
if runtime.GOOS == "linux" {
if dbg.GetDebugSymbol() {
fmt.Println("getSysLibPaths:find sys lib path from linux")
}
paths = []string{
"/usr/lib",
"/usr/local/lib",
}
paths = append(paths, getPath("/etc/ld.so.conf")...)
if dbg.GetDebugSymbol() && len(paths) == 0 {
fmt.Println("getSysLibPaths:/etc/ld.so.conf havent find any path")
}
confd := "/etc/ld.so.conf.d"
dir, err := os.Stat(confd)
if err != nil || !dir.IsDir() {
if dbg.GetDebugSymbol() {
fmt.Println("getSysLibPaths:/etc/ld.so.conf.d not found or not dir")
}
return paths
}
// todo(zzy) : wait llgo os.ReadDir support
// files, err := os.ReadDir(confd)
// if err == nil {
// for _, file := range files {
// filepath := filepath.Join(confd, file.Name())
// paths = append(paths, getPath(filepath)...)
// }
// }
}
return paths
}

func getPath(file string) []string {
if dbg.GetDebugSymbol() {
fmt.Println("getPath:from", file)
}
var paths []string
content, err := os.ReadFile(file)
if err != nil {
return paths
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
if line != "" && !strings.HasPrefix(line, "#") {
if file, err := os.Stat(line); err == nil && file.IsDir() {
paths = append(paths, line)
}
}
}
return paths
}

// finds the intersection of symbols from the dynamic library's symbol table and the symbols parsed from header files.
// It returns a list of symbols that can be externally linked.
func GetCommonSymbols(dylibSymbols []*nm.Symbol, headerSymbols map[string]*parse.SymbolInfo) []*types.SymbolInfo {
Expand Down
63 changes: 63 additions & 0 deletions _xtool/llcppsymg/syspath/syspath.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package syspath

import (
"os/exec"
"regexp"
"runtime"
"strings"
)

func GetLibPaths() []string {
var paths []string
if runtime.GOOS == "linux" {
//resolution from https://github.com/goplus/llcppg/commit/02307485db9269481297a4dc5e8449fffaa4f562
cmd := exec.Command("ld", "--verbose")
output, err := cmd.Output()
if err != nil {
panic(err)
}
return ParseLdOutput(string(output))
}
return paths
}

// Note:this function is only use in this package
// The public function name is for llgo test
func ParseLdOutput(output string) []string {
var paths []string
matches := regexp.MustCompile(`SEARCH_DIR\("=([^"]+)"\)`).FindAllStringSubmatch(output, -1)
for _, match := range matches {
paths = append(paths, match[1])
}
return paths
}

func GetIncludePaths() []string {
var paths []string
if runtime.GOOS == "linux" {
cmd := exec.Command("clang", "-E", "-v", "-x", "c", "/dev/null")
output, err := cmd.CombinedOutput()
if err != nil {
panic(err)
}
return ParseClangIncOutput(string(output))
}
return paths
}

func ParseClangIncOutput(output string) []string {
var paths []string
start := strings.Index(output, "#include <...> search starts here:")
end := strings.Index(output, "End of search list.")
if start == -1 || end == -1 {
return paths
}
content := output[start:end]
lines := strings.Split(content, "\n")
for _, line := range lines[1:] {
if path := strings.TrimSpace(line); path != "" {
paths = append(paths, path)
}
}
return paths
}
3 changes: 2 additions & 1 deletion cmd/gogensig/convert/deps.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/goplus/gogen"
"github.com/goplus/llcppg/_xtool/llcppsymg/args"
"github.com/goplus/llcppg/_xtool/llcppsymg/config/cfgparse"
"github.com/goplus/llcppg/_xtool/llcppsymg/syspath"
cfg "github.com/goplus/llcppg/cmd/gogensig/config"
"github.com/goplus/llcppg/cmd/gogensig/errs"
cppgtypes "github.com/goplus/llcppg/types"
Expand Down Expand Up @@ -164,7 +165,7 @@ func (p *PkgInfo) GetIncPaths() ([]string, []string, error) {
}
expandedIncFlags := env.ExpandEnv(p.CppgConf.CFlags)
cflags := cfgparse.ParseCFlags(expandedIncFlags)
incPaths, notFounds, err := cflags.GenHeaderFilePaths(p.CppgConf.Include)
incPaths, notFounds, err := cflags.GenHeaderFilePaths(p.CppgConf.Include, syspath.GetIncludePaths())
p.includes = incPaths
return incPaths, notFounds, err
}
Loading