Proposal: generate a layout test package for converted Go packages
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 5/5
- Tiempo estimado
- Más de una semana
- Aptitud para principiantes
- 35/100
- Tipo de issue
- Nueva funcionalidad
- Claridad
- Bastante claro
- Estado de actividad
- Activo
- Área
- build-system, testing-qa
Línea de trabajo
Start by reading llcppg's conversion and type-layout code, the configuration handling for llcppg.cfg, and the end-to-end test suite; the issue does not name specific files. Prototype the first rollout step for non-template records, generating layout_test.go and layout.cpp, then run the generated package through llgo test. Done means mismatches report expected and actual values, failures return a non-zero exit code, and the staged rollout cases are covered.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
1. Goal
llcppg converts C/C++ types into Go types that must have identical memory layouts (see the C/C++ to Go type mapping proposal). Today that guarantee rests on the conversion rules being right. Nothing checks the result.
This proposal makes llcppg generate a layout test package next to the converted package. Running go test (or llgo test) on it verifies, for every converted type:
sizeofmatches.alignofmatches.- The offset of every field matches.
- The size of every field matches.
A mismatch fails the test and names the type, the field, the expected value and the actual value.
2. Usage
After conversion, the output module contains a sibling test package:
mylib/ # converted Go package
mylib_layout/ # generated layout test package (do not edit)
layout_test.go
layout.cpp
Run it like any other test:
llgo test ./mylib_layout
llcppg generates it by default; -layout=false in the command line (or "layout": false in llcppg.cfg) turns it off. Regenerating the package overwrites it, so it is safe to wire into CI.
When a check fails, the output looks like:
--- FAIL: TestLayout/Baz
layout_test.go:42: Baz.X offset: C++ = 4, Go = 0
layout_test.go:43: Baz sizeof: C++ = 8, Go = 4
3. Where the expected values come from
There are two possible sources, and they catch different bugs.
- Static values captured at generation time. llcppg already reads the record layout from Clang when it converts a type. Writing those numbers into the test is cheap and needs no C++ compiler at test time. But it only proves the Go type agrees with what llcppg believed; if llcppg misread the layout, the test agrees with the mistake.
- Values computed by a real C++ compiler at test time. The test package includes a small C++ file that exports
sizeof,alignofandoffsetoffor every converted type. The Go test calls it and compares. This checks against the compiler that actually builds the library, so it also catches ABI and header drift.
Decision: use the second source by default. Offer -layout=static for environments that cannot build C++ code in tests, which emits the first kind instead. The two modes share the same generated Go test structure; only the origin of the expected numbers differs.
3.1 The generated C++ helper
For each type the helper exposes plain functions, with names derived from the Go type name so they are stable across regeneration:
#include <cstddef>
#include "mylib.h"
extern "C" {
size_t llcppg_layout_Baz_size() { return sizeof(baz); }
size_t llcppg_layout_Baz_align() { return alignof(baz); }
size_t llcppg_layout_Baz_off_x() { return __builtin_offsetof(baz, x); }
size_t llcppg_layout_Baz_sz_x() { return sizeof(((baz*)0)->x); }
}
__builtin_offsetof is used because offsetof is only conditionally supported for non-standard-layout types, and types with [[no_unique_address]] or base classes are common here. The helper may need -Wno-invalid-offsetof.
3.2 The generated Go test
func TestLayout(t *testing.T) {
var v mylib.Baz
check(t, "Baz sizeof", cxxSize_Baz(), unsafe.Sizeof(v))
check(t, "Baz alignof", cxxAlign_Baz(), unsafe.Alignof(v))
check(t, "Baz.X offset", cxxOff_Baz_x(), unsafe.Offsetof(v.X))
check(t, "Baz.X sizeof", cxxSz_Baz_x(), unsafe.Sizeof(v.X))
}
Each type gets its own subtest, so one failing type does not hide the others.
4. What is and is not checked
Checked
- Every converted struct/class: size and alignment.
- Every field that has a Go counterpart: offset and size.
- Embedded base classes: offset and size, using the embedded field name.
- Instantiated templates (see 4.2).
Skipped
- Generated padding fields (
_llcppg_paddingN). They exist to make the other offsets right; they have no C++ counterpart. - Bit-fields and union members. Their Go representation is defined by their own proposals; only the size and alignment of the enclosing type are checked. These skips are listed in the test output so they are visible.
- Types llcppg skipped during conversion.
4.1 Standalone empty classes
By design (known limitation in the type mapping document), an empty C++ class has sizeof 1 and its Go counterpart has unsafe.Sizeof 0. The test records this as an expected exception rather than a failure: it asserts C++ size is 1 and Go size is 0. If either side changes, the test fails, so the exception cannot silently drift.
Types that merely contain an empty class are checked normally. That is the case the padding rules exist for.
4.2 Templates
llcppg cannot know template arguments, but the layout directives (//llgo:padding, //llgo:padding-if, //llgo:no-padding) only make sense when verified on concrete instantiations. The test package therefore checks a set of instantiations:
- Instantiations that already appear in the converted headers (as field types, typedefs or base classes). These are collected automatically.
- Extra instantiations listed in
llcppg.cfg, so authors can cover the interesting combinations, in particular the empty-type ones.
Suggested config shape:
{
"layout": {
"instances": [
"Object<Empty, Empty>",
"Object<Empty, int>",
"Object<int, Empty>"
]
}
}
Each instance produces a C++ helper entry and a Go check on the corresponding instantiated Go type, for example mylib.Object[mylib.Empty, mylib.Empty].
The "same empty type twice" case needs explicit attention, since that is where the simple padding model breaks. llcppg should add <T, T> for every template that has more than one type parameter used as a [[no_unique_address]] member whenever T can be an empty class, even if no such instantiation appears in the headers.
5. Behavior and failure reporting
- One failure per mismatched value, with type, member, expected (C++) and actual (Go).
- A final summary line with the count of checked types, checked fields and skipped items.
- Non-zero exit code on any mismatch, so CI fails.
- Output order follows header declaration order, which keeps diffs stable.
6. Responsibilities
- llcppg generates
layout_test.goandlayout.cppfrom the same type information it used for conversion, and regenerates them whenever the package is regenerated. - LLGo builds the C++ helper together with the test and resolves the
extern "C"calls. - Library authors only run
llgo test, and may extendlayout.instancesfor templates.
7. Rollout
- Non-template structs and classes: size, alignment, field offsets and sizes.
- Embedded bases, standalone empty-class exceptions, skipped-item reporting.
- Template instantiations from headers, then config-listed instantiations.
-layout=staticmode.- Run the generated package for every package in the llcppg end-to-end test suite and in goplus/lib CI.
8. Open questions
- Package naming and location: sibling directory (
mylib_layout) versus aninternal/layouttestsubpackage of the converted module. - How to name helper functions for types in nested namespaces and for template instances so the names stay stable across regeneration.
- Whether the helper should also verify enum underlying type sizes and function pointer fields, which are layout-relevant but are not records.
- Handling of ABIs other than Itanium: offsets from a real compiler are correct by construction, but the expected-exception list in 4.1 is ABI-specific.
- Whether a failing layout check should also be offered as a generation-time warning when the C++ compiler is available, instead of waiting for tests.
- Lenguaje dominante
- Go
- Estrellas
- 39
- Forks
- 13
- Merge medio
- 1 h 28 min
- PR fusionados (30 d)
- 256
Preparar el entorno
Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de goplus/llcppg
-
bug
Dificultad 5/5 Más de una semana Aptitud para principiantes 28/100
Los mantenedores suelen responder en 1 día
-
bug
Dificultad 4/5 3-5 días Aptitud para principiantes 55/100
Los mantenedores suelen responder en 1 día
-
feature proposal
Dificultad 5/5 Más de una semana Aptitud para principiantes 18/100
Los mantenedores suelen responder en 1 día
-
Dificultad 5/5 Más de una semana Aptitud para principiantes 25/100
Los mantenedores suelen responder en 1 día
-
Architecture-Design proposal
Dificultad 5/5 Más de una semana Aptitud para principiantes 35/100
Los mantenedores suelen responder en 1 día
Todos los issues de goplus/llcppg
Issues similares
-
Say in the changelog that the text-index update cannot be rolled backPosiblemente ocupada @praetorianer777 la tomó hoy. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 88/100
praetorianer777/GoTome#275 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
SAP/crossplane-provider-btp#1118 ·
Los mantenedores suelen responder en 1 día
-
benchmark: `make setup` fails because audit-exporter builds with Go 1.25.0 while go.mod requires 1.26.0Posiblemente ocupada @xsvm la tomó hoy. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 84/100
volcano-sh/volcano#6097 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
area/infra backlog bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
praetorianer777/Stator#417 ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día