C++ API
正在寻找跨语言 FFI 契约? 请参阅
./ffi-abi.md,其中包含call、"ERROR:"前缀、 4 MiB 结果缓冲区,以及cxx::bridge命名空间kcl_lib。kcl_lib.hpp中的每个类型化辅助函数都是由cxx基于该单一调度器(dispatcher)生成的轻量 C++ 包装。
C++ API 通过
cxx bridge 构建于 kcl_api::call 之上,并在
kcl_lib:: 命名空间中暴露完整的 KclService + BuiltinService 接口。
所有 *Args / *Result 类型均由 spec/spec.proto 生成,每个类型化包装
函数都会返回 Result<T>,并将调度器返回的 "ERROR:..." 回复映射为
kcl_lib::KclError。
环境要求
- CMake >= 3.10
- 支持 C++17 的 C++ 编译器
- Cargo
安装
CMake
你可以使用 FetchContent 将 KCL C++ Lib 添加到你的项目中。
FetchContent_Declare(
kcl-lib
GIT_REPOSITORY https://github.com/kcl-lang/lib.git
GIT_TAG v0.13.0 # You can change the GitHub branch tag.
SOURCE_SUBDIR cpp
)
FetchContent_MakeAvailable(kcl-lib)
或者你可以下载源码并将其添加到你的项目中。
mkdir third_party
cd third_party
git clone https://github.com/kcl-lang/lib.git
更新你的 CMake 文件。
add_subdirectory(third_party/lib/cpp)
target_link_libraries(your_target kcl-lib-cpp)
API 参考
exec_program
执行 KCL 文件并传入参数,返回 JSON/YAML 结果。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::ExecProgramArgs {
.k_filename_list = { "../test_data/schema.k" },
};
auto result = kcl_lib::exec_program(args);
std::cout << result.yaml_result.c_str() << std::endl;
return 0;
}
parse_file
将单个 KCL 文件解析为 Module AST JSON 字符串,并返回导入依赖与解析错误信息。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::ParseFileArgs {
.path = "../test_data/schema.k",
};
auto result = kcl_lib::parse_file(args);
std::cout << result.deps.size() << std::endl;
std::cout << result.errors.size() << std::endl;
std::cout << result.ast_json.c_str() << std::endl;
return 0;
}
parse_program
通过入口文件解析 KCL 程序,并返回 AST JSON 字符串。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::ParseProgramArgs {
.paths = { "../test_data/schema.k" },
};
auto result = kcl_lib::parse_program(args);
std::cout << result.paths[0].c_str() << std::endl;
std::cout << result.errors.size() << std::endl;
std::cout << result.ast_json.c_str() << std::endl;
return 0;
}
load_package
load_package 为用户提供解析 KCL 程序以及符号、类型、定义等语义模型信息的能力。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto parse_args = kcl_lib::ParseProgramArgs {
.paths = { "../test_data/schema.k" },
};
auto args = kcl_lib::LoadPackageArgs {
.resolve_ast = true,
};
args.parse_args = kcl_lib::OptionalParseProgramArgs {
.has_value = true,
.value = parse_args,
};
auto result = kcl_lib::load_package(args);
std::cout << result.symbols[0].value.ty.value.c_str() << std::endl;
return 0;
}
list_variables
list_variables 为用户提供解析 KCL 程序并按规格获取所有变量的能力。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::ListVariablesArgs {
.files = { "../test_data/schema.k" },
};
auto result = kcl_lib::list_variables(args);
std::cout << result.variables[0].value[0].value.c_str() << std::endl;
return 0;
}
list_options
list_options 为用户提供解析 KCL 程序并获取所有 option 信息的能力。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::ParseProgramArgs {
.paths = { "../test_data/option/main.k" },
};
auto result = kcl_lib::list_options(args);
std::cout << result.options[0].name.c_str() << std::endl;
std::cout << result.options[1].name.c_str() << std::endl;
std::cout << result.options[2].name.c_str() << std::endl;
return 0;
}
get_schema_type_mapping
获取程序中定义的 schema 类型映射。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto exec_args = kcl_lib::ExecProgramArgs {
.k_filename_list = { "../test_data/schema.k" },
};
auto args = kcl_lib::GetSchemaTypeMappingArgs();
args.exec_args = kcl_lib::OptionalExecProgramArgs {
.has_value = true,
.value = exec_args,
};
auto result = kcl_lib::get_schema_type_mapping(args);
std::cout << result.schema_type_mapping[0].key.c_str() << std::endl;
std::cout << result.schema_type_mapping[0].value.properties[0].key.c_str() << std::endl;
std::cout << result.schema_type_mapping[0].value.properties[0].value.ty.c_str() << std::endl;
return 0;
}
get_schema_type_mapping_under_path
获取程序及其依赖包中定义的 schema 类型映射,并以包名作为键。
与 get_schema_type_mapping 不同,从外部依赖包导入的 schema 会以其所属包名
作为键,而不是被合并到 __main__ 下。
示例
#include "kcl_lib.hpp"
#include <filesystem>
#include <iostream>
int main()
{
auto root = std::filesystem::canonical(std::filesystem::current_path() / "test_data" / "get_schema_ty_under_path");
auto exec_args = kcl_lib::ExecProgramArgs{
.k_filename_list = {(root / "aaa").string()},
.external_pkgs = {kcl_lib::ExternalPkg{
.pkg_name = "bbb",
.pkg_path = (root / "bbb").string(),
}},
};
auto args = kcl_lib::GetSchemaTypeMappingArgs{
.exec_args = kcl_lib::OptionalExecProgramArgs{
.has_value = true,
.value = exec_args,
},
.schema_name = "",
};
auto result = kcl_lib::get_schema_type_mapping_under_path(args);
for (auto &entry : result.schema_type_mapping)
{
std::cout << "package: " << entry.key.c_str() << std::endl;
}
return 0;
}
override_file
使用参数覆盖 KCL 文件。更多覆盖规范说明,请参阅 https://www.kcl-lang.io/docs/user_docs/guides/automation。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::OverrideFileArgs {
.file = { "../test_data/override_file/main.k" },
.specs = { "b.a=2" },
};
auto result = kcl_lib::override_file(args);
std::cout << result.result << std::endl;
std::cout << result.parse_errors.size() << std::endl;
return 0;
}
format_code
格式化代码源文件。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::FormatCodeArgs {
.source = "schema Person:\n"
" name: str\n"
" age: int\n"
" check:\n"
" 0 < age < 120\n",
};
auto result = kcl_lib::format_code(args);
std::cout << result.formatted.c_str() << std::endl;
return 0;
}
format_path
格式化 KCL 文件或包含 KCL 文件的目录路径,并返回发生变更的文件路径。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::FormatPathArgs {
.path = "../test_data/format_path/test.k",
};
auto result = kcl_lib::format_path(args);
std::cout << result.changed_paths.size() << std::endl;
return 0;
}
lint_path
对文件执行 lint 检查,并返回包含错误和警告在内的错误信息。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::LintPathArgs {
.paths = { "../test_data/lint_path/test-lint.k" }
};
auto result = kcl_lib::lint_path(args);
std::cout << result.results[0].c_str() << std::endl;
return 0;
}
validate_code
使用 schema 以及 JSON/YAML 数据字符串对代码进行校验。
示例
#include "kcl_lib.hpp"
#include <iostream>
int validate(const char* code_str, const char* data_str)
{
auto args = kcl_lib::ValidateCodeArgs {
.code = code_str,
.data = data_str,
};
auto result = kcl_lib::validate_code(args);
std::cout << result.success << std::endl;
std::cout << result.err_message.c_str() << std::endl;
return 0;
}
int main()
{
const char* code_str = "schema Person:\n"
" name: str\n"
" age: int\n"
" check:\n"
" 0 < age < 120\n";
const char* data_str = "{\"name\": \"Alice\", \"age\": 10}";
const char* error_data_str = "{\"name\": \"Alice\", \"age\": 1110}";
validate(code_str, data_str);
validate(code_str, error_data_str);
return 0;
}
运行 ValidateAPI 示例。
./validate_api
rename
重命名文件中目标符号的所有出现位置。如果文件中包含需要重命名的符号, 该 API 将重写这些文件,并返回发生变化的文件路径。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::RenameArgs {
.package_root = "../test_data/rename",
.symbol_path = "a",
.file_paths = { "../test_data/rename/main.k" },
.new_name = "a",
};
auto result = kcl_lib::rename(args);
std::cout << result.changed_files[0].c_str() << std::endl;
return 0;
}
rename_code
重命名目标符号的所有出现位置,并在代码发生变化时返回修改后的代码。 该 API 不会重写文件,而是返回修改后的代码。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::RenameCodeArgs {
.package_root = "/mock/path",
.symbol_path = "a",
.source_codes = { {
.key = "/mock/path/main.k",
.value = "a = 1\nb = a\nc = a",
} },
.new_name = "a2",
};
auto result = kcl_lib::rename_code(args);
std::cout << result.changed_codes[0].value.c_str() << std::endl;
return 0;
}
test
使用测试参数对 KCL 包运行测试。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::TestArgs {
.pkg_list = { "../test_data/testing/..." },
};
auto result = kcl_lib::test(args);
std::cout << result.info[0].name.c_str() << std::endl;
return 0;
}
load_settings_files
加载 kcl.yaml 中定义的配置文件配置。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::LoadSettingsFilesArgs {
.work_dir = "../test_data/settings",
.files = { "../test_data/settings/kcl.yaml" },
};
auto result = kcl_lib::load_settings_files(args);
std::cout << result.kcl_cli_configs.value.files.size() << std::endl;
std::cout << result.kcl_cli_configs.value.strict_range_check << std::endl;
std::cout << result.kcl_options[0].key.c_str() << std::endl;
std::cout << result.kcl_options[0].value.c_str() << std::endl;
return 0;
}
update_dependencies
下载并更新 kcl.mod 文件中定义的依赖,并返回外部包名及其位置列表。
示例
module/kcl.mod 文件内容如下:
[package]
name = "mod_update"
edition = "0.0.1"
version = "0.0.1"
[dependencies]
helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" }
flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" }
C++ 代码:
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::UpdateDependenciesArgs {
.manifest_path = "../test_data/update_dependencies",
};
auto result = kcl_lib::update_dependencies(args);
std::cout << result.external_pkgs[0].pkg_name.c_str() << std::endl;
std::cout << result.external_pkgs[1].pkg_name.c_str() << std::endl;
return 0;
}
使用外部依赖调用 exec_program
示例
module/kcl.mod 文件内容如下:
[package]
name = "mod_update"
edition = "0.0.1"
version = "0.0.1"
[dependencies]
helloworld = { oci = "oci://ghcr.io/kcl-lang/helloworld", tag = "0.1.0" }
flask = { git = "https://github.com/kcl-lang/flask-demo-kcl-manifests", commit = "ade147b" }
module/main.k 文件内容如下:
import helloworld
import flask
a = helloworld.The_first_kcl_program
C++ 代码:
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::UpdateDependenciesArgs {
.manifest_path = "../test_data/update_dependencies",
};
auto result = kcl_lib::update_dependencies(args);
auto exec_args = kcl_lib::ExecProgramArgs {
.k_filename_list = { "../test_data/update_dependencies/main.k" },
.external_pkgs = result.external_pkgs,
};
auto exec_result = kcl_lib::exec_program(exec_args);
std::cout << exec_result.yaml_result.c_str() << std::endl;
return 0;
}
get_version
返回 KCL 服务的版本信息。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto result = kcl_lib::get_version();
std::cout << result.checksum.c_str() << std::endl;
std::cout << result.git_sha.c_str() << std::endl;
std::cout << result.version.c_str() << std::endl;
std::cout << result.version_info.c_str() << std::endl;
return 0;
}
(具体的 version / checksum / git_sha 值随发布版本而变化;
请仅断言其非空。)
ping
通过调度器往返回送一个值。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto args = kcl_lib::PingArgs { .value = "hello" };
auto result = kcl_lib::ping(args);
std::cout << result.value.c_str() << std::endl; // -> "hello"
return 0;
}
list_method
列出底层运行时所支持的 KCL 服务方法名称。
示例
#include "kcl_lib.hpp"
#include <iostream>
int main()
{
auto result = kcl_lib::list_method();
for (const auto& name : result.method_name_list) {
std::cout << name.c_str() << std::endl;
}
return 0;
}
注意事项
旧的 BuildProgram 与 ExecArtifact RPC 已在 v0.13.0 中从
spec/spec.proto 中移除(请参阅
lib commit 815acac);
kcl_lib:: 调度器不再识别它们。如果你之前调用过
kcl_lib::build_program(...) 或 kcl_lib::exec_artifact(...),
请切换至 kcl_lib::exec_program(...)。