Skip to content

Commit

Permalink
Merge pull request kcl-lang#124 from Peefy/feat-cgo-api
Browse files Browse the repository at this point in the history
feat: move native cgo API to the lib repo
  • Loading branch information
Peefy authored Jul 26, 2024
2 parents 08bc5c2 + 6c7bfe2 commit 0f8d99f
Show file tree
Hide file tree
Showing 18 changed files with 1,081 additions and 1,030 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/c-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ jobs:
defaults:
run:
working-directory: "c"
runs-on: ubuntu-latest
strategy:
matrix:
os: [macos-12, macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install Rust
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/cpp-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ jobs:
defaults:
run:
working-directory: "cpp"
runs-on: ubuntu-latest
strategy:
matrix:
os: [macos-12, macos-latest, ubuntu-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Install dependencies
if: "contains(matrix.os, 'ubuntu-latest')"
run: |
sudo apt-get update
sudo apt-get install libgtest-dev ninja-build
Expand Down
49 changes: 49 additions & 0 deletions go/api/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package api

// KCL service client interface.
type ServiceClient interface {
// Ping KclvmService, return the same value as the parameter
Ping(in *Ping_Args) (out *Ping_Result, err error)
// Execute KCL file with arguments and return the JSON/YAML result.
ExecProgram(in *ExecProgram_Args) (out *ExecProgram_Result, err error)
// Depreciated: Please use the env.EnableFastEvalMode() and c.ExecutProgram method and will be removed in v0.11.0.
BuildProgram(in *BuildProgram_Args) (out *BuildProgram_Result, err error)
// Depreciated: Please use the env.EnableFastEvalMode() and c.ExecutProgram method and will be removed in v0.11.0.
ExecArtifact(in *ExecArtifact_Args) (out *ExecProgram_Result, err error)
// Parse KCL single file to Module AST JSON string with import dependencies and parse errors.
ParseFile(in *ParseFile_Args) (out *ParseFile_Result, err error)
// Parse KCL program with entry files and return the AST JSON string.
ParseProgram(in *ParseProgram_Args) (out *ParseProgram_Result, err error)
// ListOptions provides users with the ability to parse KCL program and get all option information.
ListOptions(in *ParseProgram_Args) (out *ListOptions_Result, err error)
// ListVariables provides users with the ability to parse KCL program and get all variables by specs.
ListVariables(in *ListVariables_Args) (out *ListVariables_Result, err error)
// LoadPackage provides users with the ability to parse KCL program and semantic model information including symbols, types, definitions, etc.
LoadPackage(in *LoadPackage_Args) (out *LoadPackage_Result, err error)
// Format the code source.
FormatCode(in *FormatCode_Args) (out *FormatCode_Result, err error)
// Format KCL file or directory path contains KCL files and returns the changed file paths.
FormatPath(in *FormatPath_Args) (out *FormatPath_Result, err error)
// Lint files and return error messages including errors and warnings.
LintPath(in *LintPath_Args) (out *LintPath_Result, err error)
// Override KCL file with arguments. See [https://www.kcl-lang.io/docs/user_docs/guides/automation](https://www.kcl-lang.io/docs/user_docs/guides/automation) for more override spec guide.
OverrideFile(in *OverrideFile_Args) (out *OverrideFile_Result, err error)
// Get schema type mapping defined in the program.
GetSchemaTypeMapping(in *GetSchemaTypeMapping_Args) (out *GetSchemaTypeMapping_Result, err error)
// Validate code using schema and JSON/YAML data strings.
ValidateCode(in *ValidateCode_Args) (out *ValidateCode_Result, err error)
// List dependencies files of input paths.
ListDepFiles(in *ListDepFiles_Args) (out *ListDepFiles_Result, err error)
// Load the setting file config defined in `kcl.yaml`.
LoadSettingsFiles(in *LoadSettingsFiles_Args) (out *LoadSettingsFiles_Result, err error)
// Rename all the occurrences of the target symbol in the files. This API will rewrite files if they contain symbols to be renamed. Return the file paths that got changed.
Rename(in *Rename_Args) (out *Rename_Result, err error)
// Rename all the occurrences of the target symbol and return the modified code if any code has been changed. This API won't rewrite files but return the changed code.
RenameCode(in *RenameCode_Args) (out *RenameCode_Result, err error)
// Test KCL packages with test arguments.
Test(in *Test_Args) (out *Test_Result, err error)
// Download and update dependencies defined in the `kcl.mod` file and return the external package name and location list.
UpdateDependencies(in *UpdateDependencies_Args) (out *UpdateDependencies_Result, err error)
// GetVersion KclvmService, return the kclvm service version information
GetVersion(in *GetVersion_Args) (out *GetVersion_Result, err error)
}
9 changes: 9 additions & 0 deletions go/env/env.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package env

import "os"

// Enable the fast eval mode.
func EnableFastEvalMode() {
// Set the fast eval mode for KCL
os.Setenv("KCL_FAST_EVAL", "1")
}
37 changes: 37 additions & 0 deletions go/include/kclvm_cli_cdylib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#ifndef KCL_LIB_H
#define KCL_LIB_H

#include <stdint.h>
#include <stdlib.h>

#ifndef KCL_API_EXTERN
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(LIBKCL_STATIC)
#define KCL_API_EXTERN __declspec(dllimport)
#else
#define KCL_API_EXTERN
#endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct kclvm_service kclvm_service;

KCL_API_EXTERN kclvm_service *kclvm_service_new(uint64_t plugin_agent);

KCL_API_EXTERN void kclvm_service_delete(kclvm_service *c);

KCL_API_EXTERN void kclvm_service_free_string(const char *res);

KCL_API_EXTERN const char *kclvm_service_call_with_length(kclvm_service *c,
const char *method,
const char *args,
size_t args_len,
size_t *result_len);

#ifdef __cplusplus
} // extern "C"
#endif

#endif
51 changes: 51 additions & 0 deletions go/install/install_bin_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//go:build linux || darwin
// +build linux darwin

package install

import (
"fmt"
"os"
"path/filepath"
"runtime"
)

func installBin(binDir, binName string, content []byte, versionMatched bool) error {
binPath := findPath(binName)
if binPath == "" || !versionMatched {
if runtime.GOOS == "windows" {
binName += ".exe"
}
binPath = filepath.Join(binDir, binName)
err := os.MkdirAll(binDir, 0777)
if err != nil {
return err
}

for pass := 0; ; pass++ {
tmpFullPath := fmt.Sprintf("%s~%d", binPath, pass)
tmpFile, err := os.OpenFile(tmpFullPath, os.O_CREATE|os.O_RDWR|os.O_EXCL, 0755)
if err != nil {
if os.IsExist(err) {
continue
}
return err
}
defer func() {
tmpFile.Close()
_ = os.Remove(tmpFullPath)
}()

if _, err = tmpFile.Write(content); err != nil {
return err
}
if err := os.Rename(tmpFullPath, binPath); err != nil {
return err
}
fileMode := os.FileMode(0777)
os.Chmod(binPath, fileMode)
break
}
}
return nil
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build windows
// +build windows

package install

import (
Expand Down
3 changes: 3 additions & 0 deletions go/install/install_lib_windows.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
//go:build windows
// +build windows

package install

import lib "kcl-lang.io/lib/go/lib"
Expand Down
41 changes: 41 additions & 0 deletions go/native/cgo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//go:build !windows && cgo
// +build !windows,cgo

package native

// #cgo CFLAGS:-I${SRCDIR}/../include
// #cgo !windows LDFLAGS:-lkclvm_cli_cdylib -lm -ldl -pthread
// #cgo windows LDFLAGS:-lkclvm_cli_cdylib -lmsvcrt -luserenv -lole32 -lntdll -lws2_32 -lkernel32 -lbcrypt
// #cgo linux,amd64 LDFLAGS:-L${SRCDIR}/../lib/linux-amd64 -Wl,-rpath,${SRCDIR}/../lib/linux-amd64
// #cgo linux,arm64 LDFLAGS:-L${SRCDIR}/../lib/linux-arm64 -Wl,-rpath,${SRCDIR}/../lib/linux-arm64
// #cgo darwin,amd64 LDFLAGS:-L${SRCDIR}/../lib/darwin-amd64 -Wl,-rpath,${SRCDIR}/../lib/darwin-amd64
// #cgo darwin,arm64 LDFLAGS:-L${SRCDIR}/../lib/darwin-arm64 -Wl,-rpath,${SRCDIR}/../lib/darwin-arm64
// #cgo windows,amd64 LDFLAGS:-L${SRCDIR}/../lib/windows-amd64 -Wl,-rpath,${SRCDIR}/../lib/windows-amd64
// #include <kclvm_cli_cdylib.h>
import "C"

// NewKclvmService takes a pluginAgent and returns a pointer of capi kclvm_service.
// pluginAgent is the address of C function pointer with type :const char * (*)(const char *method,const char *args,const char *kwargs),
// in which "method" is the fully qualified name of plugin method,
// and "args" ,"kwargs" and return value of pluginAgent are JSON string
func NewKclvmService(pluginAgent C.uint64_t) *C.kclvm_service {
return C.kclvm_service_new(pluginAgent)
}

// NewKclvmService releases the memory of kclvm_service
func DeleteKclvmService(serv *C.kclvm_service) {
C.kclvm_service_delete(serv)
}

// KclvmServiceFreeString releases the memory of the return value of KclvmServiceCall
func KclvmServiceFreeString(str *C.char) {
C.kclvm_service_free_string(str)
}

// KclvmServiceCall calls kclvm service by c api
// args should be serialized as protobuf byte stream
func KclvmServiceCall(serv *C.kclvm_service, method *C.char, args *C.char, args_len C.size_t) (*C.char, C.size_t) {
var size C.size_t = 0
buf := C.kclvm_service_call_with_length(serv, method, args, args_len, &size)
return buf, size
}
Loading

0 comments on commit 0f8d99f

Please sign in to comment.