Proposal: Platform-Specific Project Layout and Output

Chiusa
#1,125 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
35/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
go
Ambito
tooling

Direzione di ricerca

Start by reading the llcppg.cfg Dir rules and tracing how the CLI selects its source and destination directories. Then check how GOOS and GOARCH are obtained and where generated output is placed. Done means platform-prefixed inputs resolve to the expected platform directory, output is written under the matching destination subdirectory, and non-platform projects retain current behavior; the proposal leaves several design questions open.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Architecture-Design configuration

Summary

llcppg currently assumes that a C/C++ library looks the same on every platform: one include directory, one generated Go package. That assumption breaks down for libraries whose headers differ per operating system and architecture, with libc being the most important example. This proposal introduces a minimal platform-awareness framework for llcppg.cfg. libc is used throughout as the motivating example, but nothing in the design is specific to it.

The core ideas are:

  1. Each platform is fully independent and lives in its own $GOOS-$GOARCH directory (for example darwin-arm64), following Go's own naming exactly.
  2. Dir in llcppg.cfg gains a mandatory $GOOS-$GOARCH/ prefix when the project is platform-specific.
  3. When converting, llcppg automatically places output under <dest-dir>/$GOOS-$GOARCH. Users never create the platform subdirectory themselves.

Motivation

libc is not one library. Each platform has a different maintainer and a different set of headers:

Platform libc provider
darwin macOS SDK (libSystem)
linux glibc, musl, or others
windows UCRT / MSVCRT

Their types, constants, and function sets differ (struct stat, errno values, O_* flags, sigaction, and so on). A single binding cannot describe all of them, and trying to merge them by hand defeats the purpose of automatic generation.

The sensible model is the one Go itself uses: treat each GOOS/GOARCH pair as its own world, generate a binding for each, and let tooling pick the right one later. This proposal only covers the first part: generating and organizing the per-platform bindings.

Project Layout

A platform-specific llcppg project looks like this:

<a-llcppg-project>/
    go.mod
    go.sum
    llcppg.cfg
    darwin-arm64/
        include/
            <headers of the library for darwin/arm64>
    linux-amd64/
        include/
            <headers of the library for linux/amd64>
    ...

Taking libc as an example: darwin-arm64/include would hold the relevant files from the macOS SDK, while linux-amd64/include would hold the headers of the Linux libc being targeted (glibc or musl, for instance).

Rules:

  • The directory name is exactly $GOOS-$GOARCH as defined by Go (darwin-arm64, linux-amd64, linux-arm64, windows-amd64, and so on). No aliases, no custom spellings.
  • Each platform directory is self-contained. It carries its own headers, and nothing is shared between platforms.
  • go.mod, go.sum, and llcppg.cfg stay at the project root and are common to all platforms.

Configuration

The Dir field

For an ordinary, platform-independent project, Dir is typically one of:

"Dir": "./include"
"Dir": "./include/..."

For a platform-specific project, Dir must instead start with the $GOOS-$GOARCH/ prefix:

"Dir": "$GOOS-$GOARCH/include"
"Dir": "$GOOS-$GOARCH/include/..."

The prefix is what tells llcppg that the project is platform-specific. The rest of the path keeps its existing meaning: a plain directory, or a directory followed by /... to include subdirectories recursively.

A complete example
{
  "name": "libc",
  "Dir": "$GOOS-$GOARCH/include/...",
  "Files": [
    "stdio.h",
    "stdlib.h",
    "string.h"
  ]
}

With this configuration and the layout above, llcppg run for darwin/arm64 reads headers from darwin-arm64/include/..., and run for linux/amd64 reads them from linux-amd64/include/.... Everything else in llcppg.cfg (prefixes, type aliases, and so on) behaves as it does today and applies to whichever platform is being converted.

Validation

llcppg should reject configurations that would silently produce confusing results:

  • A Dir that mentions $GOOS or $GOARCH anywhere other than as the leading $GOOS-$GOARCH/ segment is an error.
  • A project whose headers live under platform directories but whose Dir lacks the prefix is not detected specially; it is simply treated as a normal project. Detection is driven by the Dir prefix only.
  • If the resolved platform directory does not exist, llcppg fails with a message that names the expected path (for example darwin-arm64/include).

Output Layout

When converting, the user passes <dest-dir> exactly as before:

llcppg <dest-dir> [<src-dir>]

For a platform-specific project, llcppg does not write the generated package directly into <dest-dir>. It appends the platform directory automatically:

<dest-dir>/
    darwin-arm64/
        <generated Go package for darwin/arm64>

and for another platform:

<dest-dir>/
    linux-amd64/
        <generated Go package for linux/amd64>

Key points:

  • The user never creates darwin-arm64 (or any other platform directory) by hand. It is created by llcppg.
  • The same <dest-dir> can therefore accumulate bindings for several platforms, one subdirectory each, without any collision.
  • For ordinary platform-independent projects nothing changes: output still goes straight into <dest-dir>.

Selecting the Target Platform

llcppg needs to know which platform it is converting for, so it can expand $GOOS-$GOARCH. The proposal follows Go's conventions:

  • The GOOS and GOARCH environment variables select the target platform.
  • If they are unset, llcppg uses the host platform (runtime.GOOS / runtime.GOARCH).

Because platforms are independent, producing bindings for several platforms is simply a matter of running llcppg once per platform:

GOOS=darwin GOARCH=arm64 llcppg <dest-dir> [<src-dir>]
GOOS=linux  GOARCH=amd64 llcppg <dest-dir> [<src-dir>]

Both runs write into their own subdirectory of <dest-dir>.

Compatibility

  • Existing projects are unaffected. A Dir without the $GOOS-$GOARCH/ prefix keeps the current behavior in full, including the output location.
  • No change is required to the cfg schema other than the new meaning of the Dir prefix.

Non-Goals

This proposal deliberately stops at "generate and organize per-platform bindings". The following are left for follow-up proposals:

  • A unified import path that automatically selects the right platform package at build time (for example via build constraints or a facade package).
  • Sharing or deduplicating declarations across platforms.
  • Fetching or vendoring SDK headers for a platform; the headers are provided in the platform directory by the project author.

Open Questions

  1. Concrete prefixes in Dir. Should Dir also be allowed to name a concrete platform (for example darwin-arm64/include) to pin a project to one platform, or must it always use the $GOOS-$GOARCH placeholder form?
  2. Go package path. The generated package lands in <dest-dir>/darwin-arm64, so its import path ends with the platform directory. A follow-up proposal should decide how consumers import a platform-neutral name on top of this.
  3. Cross-conversion. Running llcppg on a Linux host for darwin/arm64 requires the Darwin headers to be parsed with the right target triple. The framework allows it through GOOS/GOARCH, but the clang invocation details (target triple, sysroot) need to be specified.
  4. Architecture-independent platforms. Some systems may want a single directory per OS (linux) rather than per OS/arch pair. This proposal sticks to Go's $GOOS-$GOARCH form; a coarser grouping can be considered later if real cases appear.
Lingua principale
Go
Stelle
40
Fork
13
Merge medio
2h 4m
PR unite (30g)
143

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di goplus/llcppg

Tutte le issue di goplus/llcppg

Issue simili

Altre issue su Go

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.