Proposal: Platform-aware configuration and generation in llcppg

Đã đóng
#1,124 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
30/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
go
Lĩnh vực
build-system, tooling

Hướng nghiên cứu

Read tool/gen.go to trace configuration selection and generation, then inspect tool.Config.NewPackage and clang/clang.go for target argument propagation. Check xtool/env/cstdlib/stdlib.go for standard library discovery and require explicit Stdlib for recognized platform configurations. Done means ordinary and single-platform inputs retain their behavior, direct platform children generate into per-platform destinations with errors collected across failures, and the specified target and header rules are honored.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

configuration proposal

1. Summary

Introduce a platform-aware configuration and generation model in llcppg for C/C++ libraries whose bindings vary by target. Organize platform configurations in directories named GOOS-GOARCH[-<option>], each containing llcppg.cfg. Use the existing command arguments to select an ordinary configuration, one platform configuration, or a platform collection. A root llcppg.cfg selects single-configuration processing; only its absence triggers discovery in direct platform child directories. llarhub/libc is a concrete use case for this general model.

2. User Stories / Motivation

A binding maintainer may need separate configurations when a C/C++ library exposes different headers, declarations, macro values, or type layouts for different targets.

llarhub/libc illustrates this need: platforms can use different libc implementations, and the same implementation can expose different declarations or macro values under different target macros. For example, headers may select different branches for __x86_64__ and __aarch64__.

The generation input therefore needs both a target platform and matching library and system headers. Clang can parse for another target when given these inputs; a matching host machine is not required.

Maintainers need to select either an entire platform collection or one platform directly. Existing ordinary configurations must remain usable. For the initial libc use case, each platform uses its documented default libc; an optional suffix allows musl or another implementation to be distinguished later.

3. Current Workaround

Separate configurations can already be selected through llcppg's source-directory argument, one invocation at a time. However, the configuration-to-parser path does not currently pass a target to libclang. The proposal adds the association between directory and target, plus automatic discovery of a platform collection.

4. Goals

  • Keep each platform identity, generation configuration, and target header environment together.
  • Support ordinary, single-platform, and automatic platform-collection input through the existing positional arguments.
  • Preserve ordinary generation and the destination behavior of single-configuration invocations.

5. Out of Scope

  • The llcppg -merge algorithm.
  • GCC support and implementation of musl bindings; musl illustrates the naming extension.
  • Automatic Git commits, pushes, or branch switches.

Automatic processing writes each platform to <dest>/<platform>, continues after a platform fails, and returns the collected errors after processing the remaining platforms.

6. Proposal

6.1 Design Rule

The selected configuration provides generation settings and matching headers. When it belongs to a platform directory, that directory provides the target identity. The target and headers determine preprocessing and type parsing independently of the host running llcppg.

Configuration count and target selection are separate decisions: a directly selected platform directory is a single-configuration invocation with an explicit directory-derived target.

6.2 Syntax / API / Interface

Retain the existing command form and positional argument order:

llcppg <dest-gopkg-dir> [<src-header-files-and-cfg-dir>]

The second argument defaults to the current directory. No new argument or flag is introduced.

Configuration selection follows this order:

  1. Look for llcppg.cfg directly in the selected source directory. If present, load that configuration through the existing single-configuration path. Do not scan child directories.
  2. Only if that root configuration does not exist, inspect direct child directories for platform configurations. A child qualifies when its name is one of the initially supported platform names listed in section 6.5 and it contains llcppg.cfg.
  3. If one or more qualifying children exist, enter automatic platform-collection mode and process those configurations.
  4. If neither a root configuration nor qualifying platform configurations exist, report that no configuration was found.

A root configuration read error or invalid configuration is an error, not evidence that the directory is a platform collection.

6.3 Examples as Specification

Use the following example layout. single contains an ordinary configuration; platforms has no root llcppg.cfg and contains two platform configurations.

workspace/
    single/
        llcppg.cfg
    platforms/
        linux-amd64/
            llcppg.cfg
        darwin-arm64/
            llcppg.cfg

All six calls below supply the same destination, workspace/generated. The relative spelling changes with the working directory.

Case Working directory Command Selected input
Ordinary configuration, explicit source workspace/ llcppg ./generated ./single single/llcppg.cfg
Ordinary configuration, source omitted workspace/single/ llcppg ../generated The current directory's llcppg.cfg
Automatic platform collection, explicit source workspace/ llcppg ./generated ./platforms Both direct platform configurations
Automatic platform collection, source omitted workspace/platforms/ llcppg ../generated Both direct platform configurations in the current directory
One platform, explicit source workspace/ llcppg ./generated ./platforms/linux-amd64 Only linux-amd64/llcppg.cfg, with its directory-derived target
One platform, source omitted workspace/platforms/linux-amd64/ llcppg ../../generated The current directory's llcppg.cfg, with the linux-amd64 target

In each omitted-source form, adding . as the second argument selects the same source directory. The destination argument is still required.

The ordinary calls retain existing configuration and Pkgs behavior. The collection calls automatically process both qualifying direct platform children because the selected directory has no root configuration. The single-platform calls find a root configuration in the selected directory and process only that one; its platform name supplies the target.

Single-configuration calls write directly to the supplied destination, retaining existing subpackage behavior. Collection calls write each platform under <dest>/<platform>. For the collection example above:

generated/
    linux-amd64/
        ...generated files
        llcppg.pub
    darwin-arm64/
        ...generated files
        llcppg.pub

To regenerate just the Linux result in that layout, explicitly select its destination:

llcppg ./generated/linux-amd64 ./platforms/linux-amd64

Configured subpackages remain below the platform's destination, for example generated/linux-amd64/adt/. These are filesystem paths; generation does not select, switch, commit, or push Git branches.

6.4 Boundary Cases
Condition Behavior
Root llcppg.cfg and platform children coexist Root configuration takes precedence; children are not automatically processed
Configurations exist only below deeper descendants Do not recursively discover them
Root configuration is unreadable or invalid Report the error; do not switch modes

A child directory qualifies only when both its platform name is recognized and its llcppg.cfg exists.

6.5 Platform Names and Mapping

Use GOOS-GOARCH[-<option>], with Go's platform spellings and an optional target-environment choice. The libc mappings below illustrate the option: linux-amd64-musl identifies Linux, amd64, and musl. Omitting the option uses the documented platform default, independently of the host.

Platform names remain independent of compiler-specific target spelling. The Clang mapping is:

Platform directory Target platform libc selection Clang target
linux-amd64 Linux / amd64 glibc x86_64-unknown-linux-gnu
linux-arm64 Linux / arm64 glibc aarch64-unknown-linux-gnu
darwin-amd64 Darwin / amd64 System default x86_64-apple-darwin
darwin-arm64 Darwin / arm64 System default arm64-apple-darwin
linux-amd64-musl Linux / amd64 musl x86_64-unknown-linux-musl
linux-arm64-musl Linux / arm64 musl aarch64-unknown-linux-musl

The initial implementation recognizes exactly linux-amd64, linux-arm64, darwin-amd64, and darwin-arm64. Linux defaults to glibc. The musl rows illustrate a future naming extension and are not recognized platform configurations in this increment.

6.6 Target Headers and Stdlib

The target selects compiler-provided platform macros and type/ABI interpretation. The headers supply the C/C++ declarations and target-specific definitions being interpreted. For example, a musl target needs musl headers; a target string does not provide them.

Input Responsibility
Platform directory name Target OS, architecture, and optional target-environment choice
Dir / Files Headers whose bindings are generated
Stdlib Matching standard-library include directory needed during parsing

Relative Dir and Stdlib paths remain relative to the selected configuration directory; Files remains relative to Dir. When generating libc itself, these inputs can reference the same prepared header tree.

An empty Stdlib currently triggers local Clang include discovery. A recognized platform configuration must explicitly provide Stdlib; omission returns an error instead of using the host's default header directories. Ordinary configurations retain the existing default discovery behavior. Stdlib remains an include directory, not a sysroot.

6.7 Generation and Module Responsibilities

For a selected darwin-arm64 configuration:

  1. Load its llcppg.cfg.
  2. Map the platform name to arm64-apple-darwin.
  3. Resolve Dir, Files, and Stdlib to the selected headers and matching target environment.
  4. Pass -target arm64-apple-darwin alongside language and include arguments to libclang. Conditional compilation, macros, and types are interpreted for that target before Go generation.
  5. Generate bindings from the resulting translation units.

The existing Index.ParseTranslationUnit forwards arguments to libclang. The integration needed is target propagation through the configuration-driven path. CFlags currently serves wrapper compilation, not header parsing.

The command selects configuration directories and discovers platform collections. tool.Config.NewPackage derives the target from the basename of its existing workDir argument and supplies the corresponding libclang arguments. No Target field, new CLI option, or public method parameter is added. cl consumes translation units without knowing platform directory names or Git branches.

Automatic processing reuses the existing generation functions in the same process. Each platform receives its own <dest>/<platform> destination. A failed platform contributes an error, while the remaining platforms continue. The existing global ignore-diagnostic settings are saved and restored for each generation call so one configuration cannot silence diagnostics in the next.

6.8 Example: llarhub/libc Repository Workflow

llarhub/libc applies this configuration model to its branch organization:

c branch:
    <platform>/llcppg.cfg
              |
              | generate with that platform's inputs
              v
raw branch:
    <platform>/llcppg.cfg
    <platform>/...generated bindings
              |
              | llcppg -merge (later work)
              v
main branch:
    ...merged bindings

Configurations are maintained on c; each configuration and its generated bindings are committed under the corresponding platform name on raw. The later merge produces main. This repository workflow is external to the generator. The generator writes directories; separate Git operations determine which branch records those files.

7. Error Handling

Condition Behavior
Neither input layout supplies a configuration Report that no configuration was found
Root llcppg.cfg cannot be read or parsed Preserve the error; do not try platform discovery as a fallback
A selected platform configuration cannot be read or parsed Report its configuration error
A recognized platform configuration omits Stdlib Report the missing explicit target-header directory
One platform fails during automatic processing Continue the remaining platforms and return errors labeled with their platform names
FailFast reaches its diagnostic limit Stop the current cl.NewPackage call and return an error instead of exiting the process

8. Compatibility

Keep the positional arguments, ordinary configuration behavior, Pkgs handling, and single-configuration destination semantics. Add automatic discovery only when the root configuration is absent; collection output is placed under <dest>/<platform>.

Existing public function signatures remain unchanged. A FailFast limit now returns an error from cl.NewPackage; a single CLI invocation still reports failure through its existing error path. Unexpected panics remain panics and are not converted into platform errors.

9. Alternatives Considered

Alternative Reason for the directory-based design
Organize libc configurations only by libc implementation The same implementation can expose different interfaces under different target macros
Pass the target separately on the command line Platform directories keep the target identity attached to its configuration
Use compiler triples as directory names Go platform names keep repository organization independent of compiler-specific spelling
Require generation on each target host Target parameters and matching headers allow cross-target parsing

10. Testing Strategy

Case Expected result
Ordinary root configuration, including one with platform children Preserve existing generation and Pkgs; select only the root configuration
Missing root with qualifying direct platform children Process those configurations and write each result under <dest>/<platform>
No qualifying configuration Report a missing configuration
Unreadable or invalid root configuration Report the error without switching modes
Direct platform invocation Select one configuration, derive its target, and preserve the explicit destination
Omitted source argument Apply the same selection rules to the current directory
Deeper nested configurations Do not recursively discover them
Target-specific parsing Check OS/architecture macros, header selection, and pointer size for all four targets in C and C++
Platform configuration without Stdlib Return an error without host-header discovery
Configuration error or FailFast in a collection Return the platform errors and still produce the successful platform's output
Consecutive configurations with different ignore settings Restore diagnostic settings between calls
FailFast during loading or compilation Return an error with no partial package; preserve unrelated panics

Use llgo test for implementation tests. The implementation has passed llgo test -v ./... on macOS arm64 with LLGo v1.0.9 and LLVM 22.1.8, including the six CLI input forms and C/C++ generation fixtures for all four targets. These fixtures validate target behavior with supplied test headers; they do not establish complete libc/SDK binding coverage or execution on a Linux host.

The table's six target strings were checked with Clang 22.1.8 on macOS and produced matching OS/architecture macros. This verifies target selection only; complete libc generation remains unverified. See Clang's cross-compilation documentation.

11. Summary of Changes

Area Change
Input selection Root-configuration precedence; otherwise discover direct platform children
Target inputs Associate each selected platform configuration with its target and matching headers
Parsing integration Carry that target into the existing libclang argument path
llarhub/libc use case Maintain platform configurations on c and corresponding configurations and results on raw
CLI Keep positional arguments; write collection output under <dest>/<platform> and aggregate failures
Failure boundary Return FailFast as a package-generation error and restore per-call diagnostic settings

12. Open Questions

  1. How should target SDK/libc headers be prepared or distributed for real platform configurations? The generator currently requires callers to provide the matching Stdlib directory.
  2. Which additional platform/environment options, such as musl, should be implemented after the initial four targets?
Ngôn ngữ chính
Go
Star
40
Fork
13
Merge trung bình
2 giờ
Pull request đã merge (30 ngày)
150

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của goplus/llcppg

Tất cả issue của goplus/llcppg

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.