mirror of
https://github.com/goplus/llgo.git
synced 2025-09-26 19:51:21 +08:00
add export demo and test
This commit is contained in:
7
.github/workflows/llgo.yml
vendored
7
.github/workflows/llgo.yml
vendored
@@ -125,6 +125,13 @@ jobs:
|
|||||||
export LLGO_FULL_RPATH=true
|
export LLGO_FULL_RPATH=true
|
||||||
bash .github/workflows/test_demo.sh
|
bash .github/workflows/test_demo.sh
|
||||||
|
|
||||||
|
- name: Test C header generation
|
||||||
|
run: |
|
||||||
|
echo "Testing C header generation in different build modes..."
|
||||||
|
cd _demo/go/export
|
||||||
|
chmod +x test.sh
|
||||||
|
./test.sh
|
||||||
|
|
||||||
- name: _xtool build tests
|
- name: _xtool build tests
|
||||||
run: |
|
run: |
|
||||||
cd _xtool
|
cd _xtool
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -7,6 +7,7 @@
|
|||||||
*.dll
|
*.dll
|
||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
|
*.a
|
||||||
|
|
||||||
test.db
|
test.db
|
||||||
demo.ll
|
demo.ll
|
||||||
|
1
_demo/go/export/.gitignore
vendored
Normal file
1
_demo/go/export/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
libexport.h
|
29
_demo/go/export/c/c.go
Normal file
29
_demo/go/export/c/c.go
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
package C
|
||||||
|
|
||||||
|
// XType - struct for export.go to use
|
||||||
|
type XType struct {
|
||||||
|
ID int32 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value float64 `json:"value"`
|
||||||
|
Flag bool `json:"flag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func XAdd(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Sub(a, b int64) int64 {
|
||||||
|
return a - b
|
||||||
|
}
|
||||||
|
|
||||||
|
func sub(a, b uint32) uint32 {
|
||||||
|
return a - b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Xmul(a, b float32) float32 {
|
||||||
|
return a * b
|
||||||
|
}
|
||||||
|
|
||||||
|
func Concat(a, b string) string {
|
||||||
|
return a + b
|
||||||
|
}
|
545
_demo/go/export/export.go
Normal file
545
_demo/go/export/export.go
Normal file
@@ -0,0 +1,545 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
C "github.com/goplus/llgo/_demo/go/export/c"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Small struct
|
||||||
|
type SmallStruct struct {
|
||||||
|
ID int8 `json:"id"`
|
||||||
|
Flag bool `json:"flag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Large struct
|
||||||
|
type LargeStruct struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Values [10]float64 `json:"values"`
|
||||||
|
Metadata map[string]int `json:"metadata"`
|
||||||
|
Children []SmallStruct `json:"children"`
|
||||||
|
Extra1 int32 `json:"extra1"`
|
||||||
|
Extra2 uint64 `json:"extra2"`
|
||||||
|
Extra3 float32 `json:"extra3"`
|
||||||
|
Extra4 bool `json:"extra4"`
|
||||||
|
Extra5 uintptr `json:"extra5"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self-referential struct
|
||||||
|
type Node struct {
|
||||||
|
Data int `json:"data"`
|
||||||
|
Next *Node `json:"next"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Named types
|
||||||
|
type MyInt int
|
||||||
|
type MyString string
|
||||||
|
|
||||||
|
// Complex struct with mixed arrays and slices
|
||||||
|
type ComplexData struct {
|
||||||
|
Matrix [3][4]int32 `json:"matrix"` // 2D array
|
||||||
|
Slices [][]string `json:"slices"` // slice of slices - commented out
|
||||||
|
IntArray [5]int `json:"int_array"` // 1D array
|
||||||
|
DataList []float64 `json:"data_list"` // slice - commented out
|
||||||
|
}
|
||||||
|
|
||||||
|
//export HelloWorld
|
||||||
|
func HelloWorld() {
|
||||||
|
println("Hello, World!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with small struct parameters and return values
|
||||||
|
|
||||||
|
//export CreateSmallStruct
|
||||||
|
func CreateSmallStruct(id int8, flag bool) SmallStruct {
|
||||||
|
return SmallStruct{ID: id, Flag: flag}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessSmallStruct
|
||||||
|
func ProcessSmallStruct(s SmallStruct) SmallStruct {
|
||||||
|
s.ID += 1
|
||||||
|
s.Flag = !s.Flag
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessSmallStructPtr
|
||||||
|
func ProcessSmallStructPtr(s *SmallStruct) *SmallStruct {
|
||||||
|
if s != nil {
|
||||||
|
s.ID *= 2
|
||||||
|
s.Flag = !s.Flag
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with large struct parameters and return values
|
||||||
|
|
||||||
|
//export CreateLargeStruct
|
||||||
|
func CreateLargeStruct(id int64, name string) LargeStruct {
|
||||||
|
return LargeStruct{
|
||||||
|
ID: id,
|
||||||
|
Name: name,
|
||||||
|
Values: [10]float64{1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.0},
|
||||||
|
Metadata: map[string]int{"count": 42, "size": 100},
|
||||||
|
Children: []SmallStruct{{ID: 1, Flag: true}, {ID: 2, Flag: false}},
|
||||||
|
Extra1: 12345,
|
||||||
|
Extra2: 67890,
|
||||||
|
Extra3: 3.14,
|
||||||
|
Extra4: true,
|
||||||
|
Extra5: 0x1000,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessLargeStruct
|
||||||
|
func ProcessLargeStruct(ls LargeStruct) int64 {
|
||||||
|
total := ls.ID + int64(len(ls.Name))
|
||||||
|
for _, v := range ls.Values {
|
||||||
|
total += int64(v)
|
||||||
|
}
|
||||||
|
total += int64(len(ls.Children))
|
||||||
|
total += int64(ls.Extra1) + int64(ls.Extra2) + int64(ls.Extra3)
|
||||||
|
if ls.Extra4 {
|
||||||
|
total += 1000
|
||||||
|
}
|
||||||
|
total += int64(ls.Extra5)
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessLargeStructPtr
|
||||||
|
func ProcessLargeStructPtr(ls *LargeStruct) *LargeStruct {
|
||||||
|
if ls != nil {
|
||||||
|
ls.ID += 100
|
||||||
|
ls.Name = "processed_" + ls.Name
|
||||||
|
ls.Extra1 *= 2
|
||||||
|
ls.Extra4 = !ls.Extra4
|
||||||
|
}
|
||||||
|
return ls
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with self-referential struct
|
||||||
|
|
||||||
|
//export CreateNode
|
||||||
|
func CreateNode(data int) *Node {
|
||||||
|
return &Node{Data: data, Next: nil}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export LinkNodes
|
||||||
|
func LinkNodes(first, second *Node) {
|
||||||
|
if first != nil {
|
||||||
|
first.Next = second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export TraverseNodes
|
||||||
|
func TraverseNodes(head *Node) int {
|
||||||
|
count := 0
|
||||||
|
current := head
|
||||||
|
for current != nil {
|
||||||
|
count++
|
||||||
|
current = current.Next
|
||||||
|
if count > 100 { // Safety check
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions covering all basic types
|
||||||
|
|
||||||
|
//export ProcessBool
|
||||||
|
func ProcessBool(b bool) bool {
|
||||||
|
return !b
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessInt8
|
||||||
|
func ProcessInt8(x int8) int8 {
|
||||||
|
return x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUint8
|
||||||
|
func ProcessUint8(x uint8) uint8 {
|
||||||
|
return x + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessInt16
|
||||||
|
func ProcessInt16(x int16) int16 {
|
||||||
|
return x * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUint16
|
||||||
|
func ProcessUint16(x uint16) uint16 {
|
||||||
|
return x * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessInt32
|
||||||
|
func ProcessInt32(x int32) int32 {
|
||||||
|
return x * 3
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUint32
|
||||||
|
func ProcessUint32(x uint32) uint32 {
|
||||||
|
return x * 3
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessInt64
|
||||||
|
func ProcessInt64(x int64) int64 {
|
||||||
|
return x * 4
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUint64
|
||||||
|
func ProcessUint64(x uint64) uint64 {
|
||||||
|
return x * 4
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessInt
|
||||||
|
func ProcessInt(x int) int {
|
||||||
|
return x + 100
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUint
|
||||||
|
func ProcessUint(x uint) uint {
|
||||||
|
return x + 200
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUintptr
|
||||||
|
func ProcessUintptr(x uintptr) uintptr {
|
||||||
|
return x + 300
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessFloat32
|
||||||
|
func ProcessFloat32(x float32) float32 {
|
||||||
|
return x * 1.5
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessFloat64
|
||||||
|
func ProcessFloat64(x float64) float64 {
|
||||||
|
return x * 2.5
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessString
|
||||||
|
func ProcessString(s string) string {
|
||||||
|
return "processed_" + s
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessUnsafePointer
|
||||||
|
func ProcessUnsafePointer(p unsafe.Pointer) unsafe.Pointer {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with named types
|
||||||
|
|
||||||
|
//export ProcessMyInt
|
||||||
|
func ProcessMyInt(x MyInt) MyInt {
|
||||||
|
return x * 10
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessMyString
|
||||||
|
func ProcessMyString(s MyString) MyString {
|
||||||
|
return MyString("modified_" + string(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with arrays, slices, maps, channels
|
||||||
|
|
||||||
|
//export ProcessIntArray
|
||||||
|
func ProcessIntArray(arr [5]int) int {
|
||||||
|
total := 0
|
||||||
|
for _, v := range arr {
|
||||||
|
total += v
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
//export CreateComplexData
|
||||||
|
func CreateComplexData() ComplexData {
|
||||||
|
return ComplexData{
|
||||||
|
Matrix: [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}},
|
||||||
|
Slices: [][]string{{"helo"}},
|
||||||
|
IntArray: [5]int{10, 20, 30, 40, 50},
|
||||||
|
DataList: []float64{1.0},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessComplexData
|
||||||
|
func ProcessComplexData(data ComplexData) int32 {
|
||||||
|
// Sum all matrix elements
|
||||||
|
var sum int32
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
sum += data.Matrix[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with multidimensional arrays as parameters and return values
|
||||||
|
|
||||||
|
//export ProcessMatrix2D
|
||||||
|
func ProcessMatrix2D(matrix [3][4]int32) int32 {
|
||||||
|
var sum int32
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
sum += matrix[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
//export CreateMatrix1D
|
||||||
|
func CreateMatrix1D() [4]int32 {
|
||||||
|
return [4]int32{1, 2, 3, 4}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export CreateMatrix2D
|
||||||
|
func CreateMatrix2D() [3][4]int32 {
|
||||||
|
return [3][4]int32{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessMatrix3D
|
||||||
|
func ProcessMatrix3D(cube [2][3][4]uint8) uint32 {
|
||||||
|
var sum uint32
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
for k := 0; k < 4; k++ {
|
||||||
|
sum += uint32(cube[i][j][k])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
//export CreateMatrix3D
|
||||||
|
func CreateMatrix3D() [2][3][4]uint8 {
|
||||||
|
var cube [2][3][4]uint8
|
||||||
|
val := uint8(1)
|
||||||
|
for i := 0; i < 2; i++ {
|
||||||
|
for j := 0; j < 3; j++ {
|
||||||
|
for k := 0; k < 4; k++ {
|
||||||
|
cube[i][j][k] = val
|
||||||
|
val++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cube
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessGrid5x4
|
||||||
|
func ProcessGrid5x4(grid [5][4]float64) float64 {
|
||||||
|
var sum float64
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
sum += grid[i][j]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sum
|
||||||
|
}
|
||||||
|
|
||||||
|
//export CreateGrid5x4
|
||||||
|
func CreateGrid5x4() [5][4]float64 {
|
||||||
|
var grid [5][4]float64
|
||||||
|
val := 1.0
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
for j := 0; j < 4; j++ {
|
||||||
|
grid[i][j] = val
|
||||||
|
val += 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return grid
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessIntSlice
|
||||||
|
func ProcessIntSlice(slice []int) int {
|
||||||
|
total := 0
|
||||||
|
for _, v := range slice {
|
||||||
|
total += v
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessStringMap
|
||||||
|
func ProcessStringMap(m map[string]int) int {
|
||||||
|
total := 0
|
||||||
|
for _, v := range m {
|
||||||
|
total += v
|
||||||
|
}
|
||||||
|
return total
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessIntChannel
|
||||||
|
func ProcessIntChannel(ch chan int) int {
|
||||||
|
select {
|
||||||
|
case val := <-ch:
|
||||||
|
return val
|
||||||
|
default:
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with interface
|
||||||
|
|
||||||
|
//export ProcessInterface
|
||||||
|
func ProcessInterface(i interface{}) int {
|
||||||
|
switch v := i.(type) {
|
||||||
|
case int:
|
||||||
|
return v
|
||||||
|
case string:
|
||||||
|
return len(v)
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions with various parameter counts
|
||||||
|
|
||||||
|
//export NoParams
|
||||||
|
func NoParams() int {
|
||||||
|
return 42
|
||||||
|
}
|
||||||
|
|
||||||
|
//export OneParam
|
||||||
|
func OneParam(x int) int {
|
||||||
|
return x * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//export TwoParams
|
||||||
|
func TwoParams(a int, b string) string {
|
||||||
|
return string(rune(a)) + b
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ThreeParams
|
||||||
|
func ThreeParams(a int32, b float64, c bool) float64 {
|
||||||
|
result := float64(a) + b
|
||||||
|
if c {
|
||||||
|
result *= 2
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
//export MultipleParams
|
||||||
|
func MultipleParams(a int8, b uint16, c int32, d uint64, e float32, f float64, g string, h bool) string {
|
||||||
|
return g + "_processed"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions returning no value
|
||||||
|
|
||||||
|
//export NoReturn
|
||||||
|
func NoReturn(message string) {
|
||||||
|
println("Message:", message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions using XType from c package
|
||||||
|
|
||||||
|
//export CreateXType
|
||||||
|
func CreateXType(id int32, name string, value float64, flag bool) C.XType {
|
||||||
|
return C.XType{
|
||||||
|
ID: id,
|
||||||
|
Name: name,
|
||||||
|
Value: value,
|
||||||
|
Flag: flag,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessXType
|
||||||
|
func ProcessXType(x C.XType) C.XType {
|
||||||
|
x.ID += 100
|
||||||
|
x.Name = "processed_" + x.Name
|
||||||
|
x.Value *= 2.0
|
||||||
|
x.Flag = !x.Flag
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
//export ProcessXTypePtr
|
||||||
|
func ProcessXTypePtr(x *C.XType) *C.XType {
|
||||||
|
if x != nil {
|
||||||
|
x.ID *= 2
|
||||||
|
x.Name = "ptr_" + x.Name
|
||||||
|
x.Value += 10.0
|
||||||
|
x.Flag = !x.Flag
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("=== Export Demo ===")
|
||||||
|
|
||||||
|
// Test small struct
|
||||||
|
small := CreateSmallStruct(5, true)
|
||||||
|
println("Small struct:", small.ID, small.Flag)
|
||||||
|
|
||||||
|
processed := ProcessSmallStruct(small)
|
||||||
|
println("Processed small:", processed.ID, processed.Flag)
|
||||||
|
|
||||||
|
// Test large struct
|
||||||
|
large := CreateLargeStruct(12345, "test")
|
||||||
|
println("Large struct ID:", large.ID, "Name:", large.Name)
|
||||||
|
|
||||||
|
total := ProcessLargeStruct(large)
|
||||||
|
println("Large struct total:", total)
|
||||||
|
|
||||||
|
// Test self-referential struct
|
||||||
|
node1 := CreateNode(100)
|
||||||
|
node2 := CreateNode(200)
|
||||||
|
LinkNodes(node1, node2)
|
||||||
|
|
||||||
|
count := TraverseNodes(node1)
|
||||||
|
println("Node count:", count)
|
||||||
|
|
||||||
|
// Test basic types
|
||||||
|
println("Bool:", ProcessBool(true))
|
||||||
|
println("Int8:", ProcessInt8(10))
|
||||||
|
println("Float32:", ProcessFloat32(3.14))
|
||||||
|
println("String:", ProcessString("hello"))
|
||||||
|
|
||||||
|
// Test named types
|
||||||
|
myInt := ProcessMyInt(MyInt(42))
|
||||||
|
println("MyInt:", int(myInt))
|
||||||
|
|
||||||
|
myStr := ProcessMyString(MyString("world"))
|
||||||
|
println("MyString:", string(myStr))
|
||||||
|
|
||||||
|
// Test collections
|
||||||
|
arr := [5]int{1, 2, 3, 4, 5}
|
||||||
|
println("Array sum:", ProcessIntArray(arr))
|
||||||
|
|
||||||
|
slice := []int{10, 20, 30}
|
||||||
|
println("Slice sum:", ProcessIntSlice(slice))
|
||||||
|
|
||||||
|
m := make(map[string]int)
|
||||||
|
m["a"] = 100
|
||||||
|
m["b"] = 200
|
||||||
|
println("Map sum:", ProcessStringMap(m))
|
||||||
|
|
||||||
|
// Test multidimensional arrays
|
||||||
|
matrix2d := CreateMatrix2D()
|
||||||
|
println("Matrix2D sum:", ProcessMatrix2D(matrix2d))
|
||||||
|
|
||||||
|
matrix3d := CreateMatrix3D()
|
||||||
|
println("Matrix3D sum:", ProcessMatrix3D(matrix3d))
|
||||||
|
|
||||||
|
grid5x4 := CreateGrid5x4()
|
||||||
|
println("Grid5x4 sum:", ProcessGrid5x4(grid5x4))
|
||||||
|
|
||||||
|
// Test complex data with multidimensional arrays
|
||||||
|
complexData := CreateComplexData()
|
||||||
|
println("ComplexData matrix sum:", ProcessComplexData(complexData))
|
||||||
|
|
||||||
|
// Test various parameter counts
|
||||||
|
println("NoParams:", NoParams())
|
||||||
|
println("OneParam:", OneParam(5))
|
||||||
|
println("TwoParams:", TwoParams(65, "_test"))
|
||||||
|
println("ThreeParams:", ThreeParams(10, 2.5, true))
|
||||||
|
println("MultipleParams:", MultipleParams(1, 2, 3, 4, 5.0, 6.0, "result", true))
|
||||||
|
|
||||||
|
// Test XType from c package
|
||||||
|
xtype := CreateXType(42, "test", 3.14, true)
|
||||||
|
println("XType:", xtype.ID, xtype.Name, xtype.Value, xtype.Flag)
|
||||||
|
|
||||||
|
processedX := ProcessXType(xtype)
|
||||||
|
println("Processed XType:", processedX.ID, processedX.Name, processedX.Value, processedX.Flag)
|
||||||
|
|
||||||
|
ptrX := ProcessXTypePtr(&xtype)
|
||||||
|
if ptrX != nil {
|
||||||
|
println("Ptr XType:", ptrX.ID, ptrX.Name, ptrX.Value, ptrX.Flag)
|
||||||
|
}
|
||||||
|
|
||||||
|
NoReturn("demo completed")
|
||||||
|
}
|
291
_demo/go/export/libexport.h.want
Normal file
291
_demo/go/export/libexport.h.want
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
/* Code generated by llgo; DO NOT EDIT. */
|
||||||
|
|
||||||
|
#ifndef __LIBEXPORT_H_
|
||||||
|
#define __LIBEXPORT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Platform-specific symbol renaming macro
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define GO_SYMBOL_RENAME(go_name) __asm("_" go_name);
|
||||||
|
#else
|
||||||
|
#define GO_SYMBOL_RENAME(go_name) __asm(go_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Go runtime types
|
||||||
|
typedef struct { const char *p; intptr_t n; } GoString;
|
||||||
|
typedef struct { void *data; intptr_t len; intptr_t cap; } GoSlice;
|
||||||
|
typedef struct { void *data; } GoMap;
|
||||||
|
typedef struct { void *data; } GoChan;
|
||||||
|
typedef struct { void *data; void *type; } GoInterface;
|
||||||
|
typedef struct { float real; float imag; } GoComplex64;
|
||||||
|
typedef struct { double real; double imag; } GoComplex128;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t Matrix[3][4];
|
||||||
|
GoSlice Slices;
|
||||||
|
intptr_t IntArray[5];
|
||||||
|
GoSlice DataList;
|
||||||
|
} main_ComplexData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double data[5][4];
|
||||||
|
} Array_double_5_4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int8_t ID;
|
||||||
|
_Bool Flag;
|
||||||
|
} main_SmallStruct;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int64_t ID;
|
||||||
|
GoString Name;
|
||||||
|
double Values[10];
|
||||||
|
GoMap Metadata;
|
||||||
|
GoSlice Children;
|
||||||
|
int32_t Extra1;
|
||||||
|
uint64_t Extra2;
|
||||||
|
float Extra3;
|
||||||
|
_Bool Extra4;
|
||||||
|
uintptr_t Extra5;
|
||||||
|
} main_LargeStruct;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t data[4];
|
||||||
|
} Array_int32_t_4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t data[3][4];
|
||||||
|
} Array_int32_t_3_4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t data[2][3][4];
|
||||||
|
} Array_uint8_t_2_3_4;
|
||||||
|
|
||||||
|
typedef struct main_Node main_Node;
|
||||||
|
struct main_Node {
|
||||||
|
intptr_t Data;
|
||||||
|
main_Node* Next;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t ID;
|
||||||
|
GoString Name;
|
||||||
|
double Value;
|
||||||
|
_Bool Flag;
|
||||||
|
} C_XType;
|
||||||
|
|
||||||
|
typedef intptr_t main_MyInt;
|
||||||
|
|
||||||
|
typedef GoString main_MyString;
|
||||||
|
|
||||||
|
GoString
|
||||||
|
Concat(GoString a, GoString b);
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
Sub(int64_t a, int64_t b);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
Add(intptr_t a, intptr_t b);
|
||||||
|
|
||||||
|
float
|
||||||
|
mul(float a, float b);
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo__demo_go_export_c_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/_demo/go/export/c.init")
|
||||||
|
|
||||||
|
main_ComplexData
|
||||||
|
CreateComplexData(void);
|
||||||
|
|
||||||
|
Array_double_5_4
|
||||||
|
CreateGrid5x4(void);
|
||||||
|
|
||||||
|
main_LargeStruct
|
||||||
|
CreateLargeStruct(int64_t id, GoString name);
|
||||||
|
|
||||||
|
Array_int32_t_4
|
||||||
|
CreateMatrix1D(void);
|
||||||
|
|
||||||
|
Array_int32_t_3_4
|
||||||
|
CreateMatrix2D(void);
|
||||||
|
|
||||||
|
Array_uint8_t_2_3_4
|
||||||
|
CreateMatrix3D(void);
|
||||||
|
|
||||||
|
main_Node*
|
||||||
|
CreateNode(intptr_t data);
|
||||||
|
|
||||||
|
main_SmallStruct
|
||||||
|
CreateSmallStruct(int8_t id, _Bool flag);
|
||||||
|
|
||||||
|
C_XType
|
||||||
|
CreateXType(int32_t id, GoString name, double value, _Bool flag);
|
||||||
|
|
||||||
|
void
|
||||||
|
HelloWorld(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
LinkNodes(main_Node* first, main_Node* second);
|
||||||
|
|
||||||
|
GoString
|
||||||
|
MultipleParams(int8_t a, uint16_t b, int32_t c, uint64_t d, float e, double f, GoString g, _Bool h);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
NoParams(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
NoReturn(GoString message);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
OneParam(intptr_t x);
|
||||||
|
|
||||||
|
_Bool
|
||||||
|
ProcessBool(_Bool b);
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
ProcessComplexData(main_ComplexData data);
|
||||||
|
|
||||||
|
float
|
||||||
|
ProcessFloat32(float x);
|
||||||
|
|
||||||
|
double
|
||||||
|
ProcessFloat64(double x);
|
||||||
|
|
||||||
|
double
|
||||||
|
ProcessGrid5x4(double grid[5][4]);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessInt(intptr_t x);
|
||||||
|
|
||||||
|
int16_t
|
||||||
|
ProcessInt16(int16_t x);
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
ProcessInt32(int32_t x);
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
ProcessInt64(int64_t x);
|
||||||
|
|
||||||
|
int8_t
|
||||||
|
ProcessInt8(int8_t x);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessIntArray(intptr_t arr[5]);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessIntChannel(GoChan ch);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessIntSlice(GoSlice slice);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessInterface(GoInterface i);
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
ProcessLargeStruct(main_LargeStruct ls);
|
||||||
|
|
||||||
|
main_LargeStruct*
|
||||||
|
ProcessLargeStructPtr(main_LargeStruct* ls);
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
ProcessMatrix2D(int32_t matrix[3][4]);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
ProcessMatrix3D(uint8_t cube[2][3][4]);
|
||||||
|
|
||||||
|
main_MyInt
|
||||||
|
ProcessMyInt(main_MyInt x);
|
||||||
|
|
||||||
|
main_MyString
|
||||||
|
ProcessMyString(main_MyString s);
|
||||||
|
|
||||||
|
main_SmallStruct
|
||||||
|
ProcessSmallStruct(main_SmallStruct s);
|
||||||
|
|
||||||
|
main_SmallStruct*
|
||||||
|
ProcessSmallStructPtr(main_SmallStruct* s);
|
||||||
|
|
||||||
|
GoString
|
||||||
|
ProcessString(GoString s);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
ProcessStringMap(GoMap m);
|
||||||
|
|
||||||
|
uintptr_t
|
||||||
|
ProcessUint(uintptr_t x);
|
||||||
|
|
||||||
|
uint16_t
|
||||||
|
ProcessUint16(uint16_t x);
|
||||||
|
|
||||||
|
uint32_t
|
||||||
|
ProcessUint32(uint32_t x);
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
ProcessUint64(uint64_t x);
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
ProcessUint8(uint8_t x);
|
||||||
|
|
||||||
|
uintptr_t
|
||||||
|
ProcessUintptr(uintptr_t x);
|
||||||
|
|
||||||
|
void*
|
||||||
|
ProcessUnsafePointer(void* p);
|
||||||
|
|
||||||
|
C_XType
|
||||||
|
ProcessXType(C_XType x);
|
||||||
|
|
||||||
|
C_XType*
|
||||||
|
ProcessXTypePtr(C_XType* x);
|
||||||
|
|
||||||
|
double
|
||||||
|
ThreeParams(int32_t a, double b, _Bool c);
|
||||||
|
|
||||||
|
intptr_t
|
||||||
|
TraverseNodes(main_Node* head);
|
||||||
|
|
||||||
|
GoString
|
||||||
|
TwoParams(intptr_t a, GoString b);
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo__demo_go_export_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/_demo/go/export.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_abi_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/abi.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_clite_bdwgc_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/bdwgc.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_clite_bitcast_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/bitcast.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_clite_debug_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/debug.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_clite_pthread_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/pthread.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_clite_pthread_sync_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/clite/pthread/sync.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_runtime_goarch_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime/goarch.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_runtime_math_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime/math.init")
|
||||||
|
|
||||||
|
void
|
||||||
|
github_com_goplus_llgo_runtime_internal_runtime_init(void) GO_SYMBOL_RENAME("github.com/goplus/llgo/runtime/internal/runtime.init")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBEXPORT_H_ */
|
239
_demo/go/export/test.sh
Executable file
239
_demo/go/export/test.sh
Executable file
@@ -0,0 +1,239 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Test script for C header generation in different build modes
|
||||||
|
# This script tests the header generation functionality with various buildmode options
|
||||||
|
|
||||||
|
set -e # Exit on any error
|
||||||
|
|
||||||
|
# Get script directory
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
# Function to print colored output
|
||||||
|
print_status() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_warning() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
print_error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to check if file exists and is not empty
|
||||||
|
check_file() {
|
||||||
|
local file="$1"
|
||||||
|
local description="$2"
|
||||||
|
|
||||||
|
if [[ -f "$file" ]]; then
|
||||||
|
if [[ -s "$file" ]]; then
|
||||||
|
print_status "$description exists and is not empty"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_error "$description exists but is empty"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_error "$description does not exist"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to compare header with expected content
|
||||||
|
compare_header() {
|
||||||
|
local header_file="$1"
|
||||||
|
local expected_file="$2"
|
||||||
|
local test_name="$3"
|
||||||
|
|
||||||
|
if [[ -f "$expected_file" ]]; then
|
||||||
|
if diff -q "$header_file" "$expected_file" >/dev/null 2>&1; then
|
||||||
|
print_status "$test_name: Header content matches expected"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
print_warning "$test_name: Header content differs from expected"
|
||||||
|
print_warning "Run 'diff $header_file $expected_file' to see differences"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "$test_name: No expected file found at $expected_file"
|
||||||
|
print_status "Generated header content:"
|
||||||
|
echo "--- START OF HEADER ---"
|
||||||
|
cat "$header_file"
|
||||||
|
echo "--- END OF HEADER ---"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to cleanup generated files
|
||||||
|
cleanup() {
|
||||||
|
local files=("$@")
|
||||||
|
for file in "${files[@]}"; do
|
||||||
|
if [[ -f "$file" ]]; then
|
||||||
|
rm -f "$file"
|
||||||
|
print_status "Cleaned up $file"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if llgo.sh exists
|
||||||
|
LLGO_SCRIPT="../../../llgo.sh"
|
||||||
|
if [[ ! -f "$LLGO_SCRIPT" ]]; then
|
||||||
|
print_error "llgo.sh not found at $LLGO_SCRIPT"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "Starting C header generation tests..."
|
||||||
|
print_status "Working directory: $SCRIPT_DIR"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Test 1: c-shared mode
|
||||||
|
print_status "=== Test 2: Building with -buildmode c-shared ==="
|
||||||
|
if $LLGO_SCRIPT build -buildmode c-shared -o export .; then
|
||||||
|
print_status "Build succeeded"
|
||||||
|
|
||||||
|
# Check generated files (different extensions on different platforms)
|
||||||
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
# macOS
|
||||||
|
check_file "libexport.dylib" "Dynamic library (libexport.dylib)"
|
||||||
|
SHARED_LIB="libexport.dylib"
|
||||||
|
else
|
||||||
|
# Linux and others
|
||||||
|
check_file "libexport.so" "Dynamic library (libexport.so)"
|
||||||
|
SHARED_LIB="libexport.so"
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_file "libexport.h" "C header (libexport.h)"
|
||||||
|
|
||||||
|
# Compare with expected header if it exists
|
||||||
|
if [[ -f "libexport.h" ]]; then
|
||||||
|
compare_header "libexport.h" "libexport.h.want" "c-shared"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test C demo with shared library
|
||||||
|
print_status "=== Testing C demo with shared library ==="
|
||||||
|
if cd use; then
|
||||||
|
if LINK_TYPE=shared make clean && LINK_TYPE=shared make; then
|
||||||
|
print_status "C demo build succeeded with shared library"
|
||||||
|
if LINK_TYPE=shared make run; then
|
||||||
|
print_status "C demo execution succeeded with shared library"
|
||||||
|
else
|
||||||
|
print_warning "C demo execution failed with shared library"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "C demo build failed with shared library"
|
||||||
|
fi
|
||||||
|
cd ..
|
||||||
|
else
|
||||||
|
print_error "Failed to enter use directory"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
cleanup "$SHARED_LIB" "libexport.h"
|
||||||
|
else
|
||||||
|
print_error "Build failed for c-shared mode"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test 2: c-archive mode
|
||||||
|
print_status "=== Test 1: Building with -buildmode c-archive ==="
|
||||||
|
if $LLGO_SCRIPT build -buildmode c-archive -o export .; then
|
||||||
|
print_status "Build succeeded"
|
||||||
|
|
||||||
|
# Check generated files
|
||||||
|
check_file "libexport.a" "Static library (libexport.a)"
|
||||||
|
check_file "libexport.h" "C header (libexport.h)"
|
||||||
|
|
||||||
|
# Compare with expected header if it exists
|
||||||
|
if [[ -f "libexport.h" ]]; then
|
||||||
|
compare_header "libexport.h" "libexport.h.want" "c-archive"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Test C demo with static library
|
||||||
|
print_status "=== Testing C demo with static library ==="
|
||||||
|
if cd use; then
|
||||||
|
if make clean && make; then
|
||||||
|
print_status "C demo build succeeded with static library"
|
||||||
|
if make run; then
|
||||||
|
print_status "C demo execution succeeded with static library"
|
||||||
|
else
|
||||||
|
print_warning "C demo execution failed with static library"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
print_warning "C demo build failed with static library"
|
||||||
|
fi
|
||||||
|
cd ..
|
||||||
|
else
|
||||||
|
print_error "Failed to enter use directory"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# # Cleanup
|
||||||
|
# cleanup "libexport.a" "libexport.h"
|
||||||
|
else
|
||||||
|
print_error "Build failed for c-archive mode"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# TODO(lijie): Uncomment if https://github.com/goplus/llgo/pull/1268 merged
|
||||||
|
# # Test 3: ESP32 target with c-archive mode
|
||||||
|
# print_status "=== Test 3: Building with -target esp32 -buildmode c-archive ==="
|
||||||
|
# if $LLGO_SCRIPT build -target esp32 -buildmode c-archive -o export .; then
|
||||||
|
# print_status "Build succeeded"
|
||||||
|
|
||||||
|
# # Check generated files
|
||||||
|
# check_file "libexport.a" "Static library for ESP32 (libexport.a)"
|
||||||
|
# check_file "libexport.h" "C header for ESP32 (libexport.h)"
|
||||||
|
|
||||||
|
# # Compare with expected header if it exists
|
||||||
|
# if [[ -f "libexport.h" ]]; then
|
||||||
|
# compare_header "libexport.h" "libexport.h.want" "esp32-c-archive"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# # Don't cleanup ESP32 files - keep them for inspection
|
||||||
|
# print_status "ESP32 build files kept for inspection"
|
||||||
|
# else
|
||||||
|
# print_error "Build failed for ESP32 target"
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# echo ""
|
||||||
|
|
||||||
|
# Final summary
|
||||||
|
print_status "=== Test Summary ==="
|
||||||
|
if [[ -f "libexport.a" ]] && [[ -f "libexport.h" ]]; then
|
||||||
|
print_status "All tests completed successfully:"
|
||||||
|
print_status " ✅ C header generation (c-archive and c-shared modes)"
|
||||||
|
print_status " ✅ C demo compilation and execution"
|
||||||
|
print_status " ✅ Cross-platform symbol renaming"
|
||||||
|
print_status " ✅ Init function export and calling"
|
||||||
|
print_status ""
|
||||||
|
print_status "Final files available:"
|
||||||
|
print_status " - libexport.a (static library)"
|
||||||
|
print_status " - libexport.h (C header file)"
|
||||||
|
print_status " - use/main.out (C demo executable)"
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "==================="
|
||||||
|
else
|
||||||
|
print_error "Some tests may have failed. Check the output above."
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show file sizes for reference
|
||||||
|
if [[ -f "libexport.a" ]]; then
|
||||||
|
SIZE=$(wc -c < libexport.a)
|
||||||
|
print_status "Static library size: $SIZE bytes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -f "libexport.h" ]]; then
|
||||||
|
LINES=$(wc -l < libexport.h)
|
||||||
|
print_status "Header file lines: $LINES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
print_status "C header generation and demo tests completed!"
|
84
_demo/go/export/use/Makefile
Normal file
84
_demo/go/export/use/Makefile
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# Makefile for C demo using Go exported library
|
||||||
|
# Use LINK_TYPE environment variable to choose library type:
|
||||||
|
# LINK_TYPE=static - Link with static library (default)
|
||||||
|
# LINK_TYPE=shared - Link with shared library
|
||||||
|
|
||||||
|
CC = clang
|
||||||
|
CFLAGS = -Wall -Wextra -std=c99
|
||||||
|
INCLUDES = -I..
|
||||||
|
TARGET = main.out
|
||||||
|
SOURCES = main.c
|
||||||
|
HEADER = ../libexport.h
|
||||||
|
|
||||||
|
# Default to static linking
|
||||||
|
LINK_TYPE ?= static
|
||||||
|
|
||||||
|
# Platform detection
|
||||||
|
UNAME_S := $(shell uname -s)
|
||||||
|
ifeq ($(UNAME_S),Darwin)
|
||||||
|
SHARED_EXT = dylib
|
||||||
|
PLATFORM_LIBS =
|
||||||
|
else
|
||||||
|
SHARED_EXT = so
|
||||||
|
PLATFORM_LIBS = $(shell pkg-config --libs libunwind 2>/dev/null || echo -lunwind)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Library and flags based on link type
|
||||||
|
ifeq ($(LINK_TYPE),shared)
|
||||||
|
BUILDMODE = c-shared
|
||||||
|
LIBRARY = ../libexport.$(SHARED_EXT)
|
||||||
|
LDFLAGS = -L.. -lexport -lpthread -lm $(shell pkg-config --libs bdw-gc || echo -lgc) $(PLATFORM_LIBS)
|
||||||
|
BUILD_MSG = "Building Go shared library..."
|
||||||
|
LINK_MSG = "Linking with shared library..."
|
||||||
|
else
|
||||||
|
BUILDMODE = c-archive
|
||||||
|
LIBRARY = ../libexport.a
|
||||||
|
LDFLAGS = $(LIBRARY) -lpthread -lm $(shell pkg-config --libs bdw-gc || echo -lgc) $(PLATFORM_LIBS)
|
||||||
|
BUILD_MSG = "Building Go static library..."
|
||||||
|
LINK_MSG = "Linking with static library..."
|
||||||
|
endif
|
||||||
|
|
||||||
|
.PHONY: all clean run build-go
|
||||||
|
|
||||||
|
all: build-go $(TARGET)
|
||||||
|
|
||||||
|
# Build the Go library first
|
||||||
|
build-go:
|
||||||
|
@echo $(BUILD_MSG)
|
||||||
|
cd .. && ../../../llgo.sh build -buildmode $(BUILDMODE) -o export .
|
||||||
|
|
||||||
|
# Build the C executable
|
||||||
|
$(TARGET): $(SOURCES) $(LIBRARY) $(HEADER)
|
||||||
|
@echo $(LINK_MSG)
|
||||||
|
$(CC) $(CFLAGS) $(INCLUDES) -o $(TARGET) $(SOURCES) $(LDFLAGS)
|
||||||
|
|
||||||
|
# Run the executable
|
||||||
|
run: $(TARGET)
|
||||||
|
@echo "Running C demo..."
|
||||||
|
ifeq ($(LINK_TYPE),shared)
|
||||||
|
@echo "Setting library path for shared library..."
|
||||||
|
LD_LIBRARY_PATH=.. DYLD_LIBRARY_PATH=.. ./$(TARGET)
|
||||||
|
else
|
||||||
|
./$(TARGET)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Clean build artifacts
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
||||||
|
rm -f ../libexport.a ../libexport.h ../libexport.so ../libexport.dylib
|
||||||
|
|
||||||
|
# Help target
|
||||||
|
help:
|
||||||
|
@echo "Available targets:"
|
||||||
|
@echo " all - Build Go library and C executable"
|
||||||
|
@echo " build-go - Build only the Go library"
|
||||||
|
@echo " run - Build and run the C demo"
|
||||||
|
@echo " clean - Clean all build artifacts"
|
||||||
|
@echo " help - Show this help message"
|
||||||
|
@echo ""
|
||||||
|
@echo "Environment variables:"
|
||||||
|
@echo " LINK_TYPE - Library type: 'static' (default) or 'shared'"
|
||||||
|
@echo ""
|
||||||
|
@echo "Examples:"
|
||||||
|
@echo " make run # Use static library"
|
||||||
|
@echo " LINK_TYPE=shared make run # Use shared library"
|
179
_demo/go/export/use/main.c
Normal file
179
_demo/go/export/use/main.c
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include "../libexport.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("=== C Export Demo ===\n");
|
||||||
|
fflush(stdout); // Force output
|
||||||
|
|
||||||
|
// Initialize packages - call init functions first
|
||||||
|
github_com_goplus_llgo__demo_go_export_c_init();
|
||||||
|
github_com_goplus_llgo__demo_go_export_init();
|
||||||
|
|
||||||
|
// Test HelloWorld
|
||||||
|
HelloWorld();
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
// Test small struct
|
||||||
|
main_SmallStruct small = CreateSmallStruct(5, 1); // 1 for true
|
||||||
|
printf("Small struct: %d %d\n", small.ID, small.Flag);
|
||||||
|
|
||||||
|
main_SmallStruct processed = ProcessSmallStruct(small);
|
||||||
|
printf("Processed small: %d %d\n", processed.ID, processed.Flag);
|
||||||
|
|
||||||
|
main_SmallStruct* ptrSmall = ProcessSmallStructPtr(&small);
|
||||||
|
if (ptrSmall != NULL) {
|
||||||
|
printf("Ptr small: %d %d\n", ptrSmall->ID, ptrSmall->Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test large struct - create GoString for name parameter
|
||||||
|
GoString name = {"test_large", 10}; // name and length
|
||||||
|
main_LargeStruct large = CreateLargeStruct(12345, name);
|
||||||
|
printf("Large struct ID: %" PRId64 "\n", large.ID);
|
||||||
|
|
||||||
|
int64_t total = ProcessLargeStruct(large);
|
||||||
|
printf("Large struct total: %" PRId64 "\n", total);
|
||||||
|
|
||||||
|
main_LargeStruct* ptrLarge = ProcessLargeStructPtr(&large);
|
||||||
|
if (ptrLarge != NULL) {
|
||||||
|
printf("Ptr large ID: %" PRId64 "\n", ptrLarge->ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test self-referential struct
|
||||||
|
main_Node* node1 = CreateNode(100);
|
||||||
|
main_Node* node2 = CreateNode(200);
|
||||||
|
LinkNodes(node1, node2);
|
||||||
|
|
||||||
|
int count = TraverseNodes(node1);
|
||||||
|
printf("Node count: %d\n", count);
|
||||||
|
|
||||||
|
// Test basic types
|
||||||
|
printf("Bool: %d\n", ProcessBool(1)); // 1 for true
|
||||||
|
printf("Int8: %d\n", ProcessInt8(10));
|
||||||
|
printf("Uint8: %d\n", ProcessUint8(10));
|
||||||
|
printf("Int16: %d\n", ProcessInt16(10));
|
||||||
|
printf("Uint16: %d\n", ProcessUint16(10));
|
||||||
|
printf("Int32: %d\n", ProcessInt32(10));
|
||||||
|
printf("Uint32: %u\n", ProcessUint32(10));
|
||||||
|
printf("Int64: %" PRId64 "\n", ProcessInt64(10));
|
||||||
|
printf("Uint64: %" PRIu64 "\n", ProcessUint64(10));
|
||||||
|
printf("Int: %ld\n", ProcessInt(10));
|
||||||
|
printf("Uint: %lu\n", ProcessUint(10));
|
||||||
|
printf("Uintptr: %lu\n", ProcessUintptr(0x1000));
|
||||||
|
printf("Float32: %f\n", ProcessFloat32(3.14f));
|
||||||
|
printf("Float64: %f\n", ProcessFloat64(3.14));
|
||||||
|
|
||||||
|
// Test unsafe pointer
|
||||||
|
int test_val = 42;
|
||||||
|
void* ptr_result = ProcessUnsafePointer(&test_val);
|
||||||
|
printf("UnsafePointer: %p\n", ptr_result);
|
||||||
|
|
||||||
|
// Test named types
|
||||||
|
main_MyInt myInt = ProcessMyInt(42);
|
||||||
|
printf("MyInt: %ld\n", (long)myInt);
|
||||||
|
|
||||||
|
// Test arrays
|
||||||
|
intptr_t arr[5] = {1, 2, 3, 4, 5};
|
||||||
|
printf("Array sum: %ld\n", ProcessIntArray(arr));
|
||||||
|
|
||||||
|
// Test complex data with multidimensional arrays
|
||||||
|
main_ComplexData complex = CreateComplexData();
|
||||||
|
printf("Complex data matrix sum: %" PRId32 "\n", ProcessComplexData(complex));
|
||||||
|
|
||||||
|
// Test interface - this is more complex in C, we'll skip for now
|
||||||
|
printf("Interface test skipped (complex in C)\n");
|
||||||
|
|
||||||
|
// Test various parameter counts
|
||||||
|
printf("NoParams: %ld\n", NoParams());
|
||||||
|
printf("OneParam: %ld\n", OneParam(5));
|
||||||
|
printf("ThreeParams: %f\n", ThreeParams(10, 2.5, 1)); // 1 for true
|
||||||
|
|
||||||
|
// Test XType from c package - create GoString for name parameter
|
||||||
|
GoString xname = {"test_x", 6}; // name and length
|
||||||
|
C_XType xtype = CreateXType(42, xname, 3.14, 1); // 1 for true
|
||||||
|
printf("XType: %d %f %d\n", xtype.ID, xtype.Value, xtype.Flag);
|
||||||
|
|
||||||
|
C_XType processedX = ProcessXType(xtype);
|
||||||
|
printf("Processed XType: %d %f %d\n", processedX.ID, processedX.Value, processedX.Flag);
|
||||||
|
|
||||||
|
C_XType* ptrX = ProcessXTypePtr(&xtype);
|
||||||
|
if (ptrX != NULL) {
|
||||||
|
printf("Ptr XType: %d %f %d\n", ptrX->ID, ptrX->Value, ptrX->Flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test multidimensional arrays
|
||||||
|
printf("\n=== Multidimensional Array Tests ===\n");
|
||||||
|
|
||||||
|
// Create and test 2D matrix [3][4]
|
||||||
|
// Note: CreateMatrix2D returns [3][4]int32, but function returns need special handling in C
|
||||||
|
printf("Testing 2D matrix functions...\n");
|
||||||
|
|
||||||
|
// Create a test 2D matrix [3][4]int32
|
||||||
|
int32_t test_matrix[3][4] = {
|
||||||
|
{1, 2, 3, 4},
|
||||||
|
{5, 6, 7, 8},
|
||||||
|
{9, 10, 11, 12}
|
||||||
|
};
|
||||||
|
int32_t matrix_sum = ProcessMatrix2D(test_matrix);
|
||||||
|
printf("Matrix2D sum: %d\n", matrix_sum);
|
||||||
|
|
||||||
|
// Create a test 3D cube [2][3][4]uint8
|
||||||
|
uint8_t test_cube[2][3][4];
|
||||||
|
uint8_t val = 1;
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
for (int j = 0; j < 3; j++) {
|
||||||
|
for (int k = 0; k < 4; k++) {
|
||||||
|
test_cube[i][j][k] = val++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t cube_sum = ProcessMatrix3D(test_cube);
|
||||||
|
printf("Matrix3D (cube) sum: %u\n", cube_sum);
|
||||||
|
|
||||||
|
// Create a test 5x4 grid [5][4]double
|
||||||
|
double test_grid[5][4];
|
||||||
|
double grid_val = 1.0;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
test_grid[i][j] = grid_val;
|
||||||
|
grid_val += 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
double grid_sum = ProcessGrid5x4(test_grid);
|
||||||
|
printf("Grid5x4 sum: %f\n", grid_sum);
|
||||||
|
|
||||||
|
// Test functions that return multidimensional arrays (as multi-level pointers)
|
||||||
|
printf("\n=== Testing Return Value Functions ===\n");
|
||||||
|
|
||||||
|
// Test CreateMatrix1D() which returns Array_int32_t_4
|
||||||
|
printf("About to call CreateMatrix1D()...\n");
|
||||||
|
fflush(stdout);
|
||||||
|
Array_int32_t_4 matrix1d = CreateMatrix1D();
|
||||||
|
printf("CreateMatrix1D() call completed\n");
|
||||||
|
printf("CreateMatrix1D() returned struct, first element: %d\n", matrix1d.data[0]);
|
||||||
|
|
||||||
|
// Test CreateMatrix2D() which returns Array_int32_t_3_4
|
||||||
|
printf("About to call CreateMatrix2D()...\n");
|
||||||
|
fflush(stdout);
|
||||||
|
Array_int32_t_3_4 matrix2d = CreateMatrix2D();
|
||||||
|
printf("CreateMatrix2D() call completed\n");
|
||||||
|
printf("CreateMatrix2D() returned struct, first element: %d\n", matrix2d.data[0][0]);
|
||||||
|
|
||||||
|
// Test CreateMatrix3D() which returns Array_uint8_t_2_3_4
|
||||||
|
Array_uint8_t_2_3_4 cube = CreateMatrix3D();
|
||||||
|
printf("CreateMatrix3D() returned struct, first element: %u\n", cube.data[0][0][0]);
|
||||||
|
|
||||||
|
// Test CreateGrid5x4() which returns Array_double_5_4
|
||||||
|
Array_double_5_4 grid = CreateGrid5x4();
|
||||||
|
printf("CreateGrid5x4() returned struct, first element: %f\n", grid.data[0][0]);
|
||||||
|
|
||||||
|
// Test NoReturn function
|
||||||
|
// Note: This function takes a string parameter which is complex to pass from C
|
||||||
|
// We'll skip it for now or pass a simple string if the binding allows
|
||||||
|
printf("NoReturn test skipped (string parameter)\n");
|
||||||
|
|
||||||
|
printf("C demo completed!\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user