From fec7e99fe5d9480e686daca297653a3ca9340b35 Mon Sep 17 00:00:00 2001 From: "fennoai[bot]" <231223108+fennoai[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 11:19:17 +0000 Subject: [PATCH 1/5] Add recp/cglm LLAR Formula Translate the Conan Center cglm recipe into an idiomatic LLAR Formula serving recp/cglm from v0.8.5. The upstream CMake build contract (options CGLM_SHARED/CGLM_STATIC/CGLM_USE_TEST, GNUInstallDirs layout, cglm.pc) is consistent across v0.8.5..v0.9.6, so one Formula covers the range. - No dependencies (cglm has none); versions.json deps empty. - Options shared (default OFF, matching Conan) and header_only (default OFF), both of which change the installed output. filter rejects the unsupported shared=ON+header_only=ON combination. - Library build uses the CMake helper; header-only installs the public headers directly, mirroring the Conan recipe. - Metadata comes from the installed cglm.pc via pkg-config. - onTest compiles and runs a consumer modeled on the Conan test_package, deriving flags from the installed output so it also passes on cache hits. Co-authored-by: fennoai[bot] <231223108+fennoai[bot]@users.noreply.github.com> Co-authored-by: MeteorsLiu <17515813+MeteorsLiu@users.noreply.github.com> --- recp/cglm/v0.8.5/Cglm_llar.gox | 179 +++++++++++++++++++++++++++++++++ recp/cglm/versions.json | 4 + 2 files changed, 183 insertions(+) create mode 100644 recp/cglm/v0.8.5/Cglm_llar.gox create mode 100644 recp/cglm/versions.json diff --git a/recp/cglm/v0.8.5/Cglm_llar.gox b/recp/cglm/v0.8.5/Cglm_llar.gox new file mode 100644 index 0000000..9905c5b --- /dev/null +++ b/recp/cglm/v0.8.5/Cglm_llar.gox @@ -0,0 +1,179 @@ +import ( + "os" + "path/filepath" + "slices" + "strings" +) + +// copyTree recursively copies the directory tree at src into dst, preserving +// the relative layout. It panics on any filesystem error. +func copyTree(src, dst string) { + entries := os.readDir(src)! + if err := os.mkdirAll(dst, 0o755); err != nil { + panic err + } + for _, entry := range entries { + s := filepath.join(src, entry.name()) + d := filepath.join(dst, entry.name()) + if entry.isDir() { + copyTree(s, d) + continue + } + data := os.readFile(s)! + if err := os.writeFile(d, data, 0o644); err != nil { + panic err + } + } +} + +// hasLibrary reports whether a cglm library artifact was installed under +// /lib. A header-only install has no such file. +func hasLibrary(installDir string) bool { + libDir := filepath.join(installDir, "lib") + entries, err := os.readDir(libDir) + if err != nil { + return false + } + for _, entry := range entries { + if strings.contains(entry.name(), "cglm") { + return true + } + } + return false +} + +const consumerProgram = `#include +#include + +int main(void) { + mat4 matrix = { + {1.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 1.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 1.0f}, + }; + vec4 vector = {1.0f, 2.0f, 3.0f, 1.0f}; + vec4 result; + + float det = glm_mat4_det(matrix); + glm_mat4_mulv(matrix, vector, result); + + printf("det=%f\n", det); + printf("result=%f %f %f %f\n", + result[0], result[1], result[2], result[3]); + return 0; +} +` + +id "recp/cglm" + +fromVer "v0.8.5" + +// cglm is an optimized C99 math library. Its CMake build produces a single +// `cglm` library from `src/`, installs public headers under `include/cglm`, +// and generates a `cglm.pc` pkg-config file. Upstream also supports a +// header-only mode where consumers use only the installed headers. +// +// Options mirror the meaningful choices of the Conan Center recipe: +// - shared: build the shared library (ON) instead of the static one (OFF). +// - header_only: install headers only and build nothing. +// The upstream CMake option CGLM_USE_TEST is always disabled; it builds the +// upstream test suite, not the installed interface. +defaults { + "shared": "OFF", + "header_only": "OFF", +} + +filter => { + for _, value := range target.options["shared"] { + if value != "ON" && value != "OFF" { + return false + } + } + for _, value := range target.options["header_only"] { + if value != "ON" && value != "OFF" { + return false + } + } + // A header-only package installs no library, so a shared/static choice is + // meaningless. Reject the combination rather than silently ignoring it. + if slices.contains(target.options["header_only"], "ON") && + slices.contains(target.options["shared"], "ON") { + return false + } + return true +} + +onBuild ctx => { + installDir := ctx.outputDir + headerOnly := slices.contains(target.options["header_only"], "ON") + + if headerOnly { + // Header-only: install the public headers exactly as they ship under + // include/cglm, matching the Conan recipe's header_only packaging. + src := filepath.join(ctx.SourceDir, "include", "cglm") + dst := filepath.join(installDir, "include", "cglm") + copyTree(src, dst) + ctx.setMetadata "-I" + filepath.join(installDir, "include") + return + } + + shared := slices.contains(target.options["shared"], "ON") + + c := cmake.new(ctx.SourceDir, ctx.SourceDir+"/_build", installDir) + c.defineBool "CGLM_SHARED", shared + c.defineBool "CGLM_STATIC", !shared + c.defineBool "CGLM_USE_TEST", false + c.configure + c.build + c.install + + // Derive consumer flags from the installed pkg-config file so metadata + // stays synchronized with the actual build (e.g. -lm on Linux/FreeBSD). + c.use installDir + capout => { + exec "pkg-config", "--cflags", "--libs", "cglm" + } + if lastErr != nil { + panic lastErr + } + ctx.setMetadata strings.trimSpace(output) +} + +onTest ctx => { + installDir := ctx.outputDir + testBuild := ctx.SourceDir + "/_consumer_build" + if err := os.mkdirAll(testBuild, 0o755); err != nil { + panic err + } + + // Consumer program mirrors the Conan test_package: include , + // compute a determinant and a matrix-vector product. + testSource := filepath.join(testBuild, "consumer.c") + if err := os.writeFile(testSource, []byte(consumerProgram), 0o644); err != nil { + panic err + } + + // Derive consumer flags from the installed output, not from ctx.Out + // metadata: on a cache hit onBuild is skipped and the build result is + // empty, but the install directory is still populated. Always add the + // header path; add link flags only when a library was installed (a + // header-only install has just headers). + flags := []string{"-I" + filepath.join(installDir, "include")} + if hasLibrary(installDir) { + flags = append(flags, "-L"+filepath.join(installDir, "lib"), "-lcglm", "-lm") + } + + binary := filepath.join(testBuild, "consumer") + args := []string{testSource, "-o", binary} + args = append(args, flags...) + exec "cc", args... + if lastErr != nil { + panic lastErr + } + + exec binary + if lastErr != nil { + panic lastErr + } +} diff --git a/recp/cglm/versions.json b/recp/cglm/versions.json new file mode 100644 index 0000000..cd77ff9 --- /dev/null +++ b/recp/cglm/versions.json @@ -0,0 +1,4 @@ +{ + "path": "recp/cglm", + "deps": {} +} From 2f1bb8c746a4f2ea941703c69e9503c8cf478573 Mon Sep 17 00:00:00 2001 From: MeteorsLiu <17515813+MeteorsLiu@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:33:08 +0000 Subject: [PATCH 2/5] recp/cglm: remove header_only option header_only is a Conan-specific packaging feature and is not needed in the LLAR Formula. Drop the option along with its filter branch, the header-only build path, and the copyTree/hasLibrary helpers that only supported it. The consumer test now always links against the installed library. --- recp/cglm/v0.8.5/Cglm_llar.gox | 80 ++++------------------------------ 1 file changed, 8 insertions(+), 72 deletions(-) diff --git a/recp/cglm/v0.8.5/Cglm_llar.gox b/recp/cglm/v0.8.5/Cglm_llar.gox index 9905c5b..67fcb78 100644 --- a/recp/cglm/v0.8.5/Cglm_llar.gox +++ b/recp/cglm/v0.8.5/Cglm_llar.gox @@ -1,47 +1,10 @@ import ( - "os" "path/filepath" + "os" "slices" "strings" ) -// copyTree recursively copies the directory tree at src into dst, preserving -// the relative layout. It panics on any filesystem error. -func copyTree(src, dst string) { - entries := os.readDir(src)! - if err := os.mkdirAll(dst, 0o755); err != nil { - panic err - } - for _, entry := range entries { - s := filepath.join(src, entry.name()) - d := filepath.join(dst, entry.name()) - if entry.isDir() { - copyTree(s, d) - continue - } - data := os.readFile(s)! - if err := os.writeFile(d, data, 0o644); err != nil { - panic err - } - } -} - -// hasLibrary reports whether a cglm library artifact was installed under -// /lib. A header-only install has no such file. -func hasLibrary(installDir string) bool { - libDir := filepath.join(installDir, "lib") - entries, err := os.readDir(libDir) - if err != nil { - return false - } - for _, entry := range entries { - if strings.contains(entry.name(), "cglm") { - return true - } - } - return false -} - const consumerProgram = `#include #include @@ -71,17 +34,14 @@ fromVer "v0.8.5" // cglm is an optimized C99 math library. Its CMake build produces a single // `cglm` library from `src/`, installs public headers under `include/cglm`, -// and generates a `cglm.pc` pkg-config file. Upstream also supports a -// header-only mode where consumers use only the installed headers. +// and generates a `cglm.pc` pkg-config file. // // Options mirror the meaningful choices of the Conan Center recipe: // - shared: build the shared library (ON) instead of the static one (OFF). -// - header_only: install headers only and build nothing. // The upstream CMake option CGLM_USE_TEST is always disabled; it builds the // upstream test suite, not the installed interface. defaults { - "shared": "OFF", - "header_only": "OFF", + "shared": "OFF", } filter => { @@ -90,34 +50,11 @@ filter => { return false } } - for _, value := range target.options["header_only"] { - if value != "ON" && value != "OFF" { - return false - } - } - // A header-only package installs no library, so a shared/static choice is - // meaningless. Reject the combination rather than silently ignoring it. - if slices.contains(target.options["header_only"], "ON") && - slices.contains(target.options["shared"], "ON") { - return false - } return true } onBuild ctx => { installDir := ctx.outputDir - headerOnly := slices.contains(target.options["header_only"], "ON") - - if headerOnly { - // Header-only: install the public headers exactly as they ship under - // include/cglm, matching the Conan recipe's header_only packaging. - src := filepath.join(ctx.SourceDir, "include", "cglm") - dst := filepath.join(installDir, "include", "cglm") - copyTree(src, dst) - ctx.setMetadata "-I" + filepath.join(installDir, "include") - return - } - shared := slices.contains(target.options["shared"], "ON") c := cmake.new(ctx.SourceDir, ctx.SourceDir+"/_build", installDir) @@ -156,12 +93,11 @@ onTest ctx => { // Derive consumer flags from the installed output, not from ctx.Out // metadata: on a cache hit onBuild is skipped and the build result is - // empty, but the install directory is still populated. Always add the - // header path; add link flags only when a library was installed (a - // header-only install has just headers). - flags := []string{"-I" + filepath.join(installDir, "include")} - if hasLibrary(installDir) { - flags = append(flags, "-L"+filepath.join(installDir, "lib"), "-lcglm", "-lm") + // empty, but the install directory is still populated. + flags := []string{ + "-I" + filepath.join(installDir, "include"), + "-L" + filepath.join(installDir, "lib"), + "-lcglm", "-lm", } binary := filepath.join(testBuild, "consumer") From 2a4354a271e2587985d3177a4820d66519253056 Mon Sep 17 00:00:00 2001 From: MeteorsLiu <17515813+MeteorsLiu@users.noreply.github.com> Date: Tue, 4 Aug 2026 05:39:58 +0000 Subject: [PATCH 3/5] recp/cglm: add version comparator for v-prefix border cglm's tags are mostly v-prefixed (v0.1.0..v0.9.6) but include a bare 0.3.0 alongside v0.3.0. The default GNU comparator orders the two spellings inconsistently at that border. Add Cglm_cmp.gox, which normalizes a missing leading 'v' before delegating to semver.Compare so the bare tag orders identically to its v-prefixed twin and the whole tag set is compared as valid Go semantic versions. --- recp/cglm/Cglm_cmp.gox | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 recp/cglm/Cglm_cmp.gox diff --git a/recp/cglm/Cglm_cmp.gox b/recp/cglm/Cglm_cmp.gox new file mode 100644 index 0000000..878760a --- /dev/null +++ b/recp/cglm/Cglm_cmp.gox @@ -0,0 +1,20 @@ +import "strings" + +// cglm's upstream tags are almost all v-prefixed (v0.1.0 .. v0.9.6), but one +// early tag ships without the prefix (0.3.0 alongside v0.3.0). The default +// GNU comparator orders the two spellings inconsistently at that border, so a +// custom comparator normalizes the prefix before comparing. +// +// Normalizing to a canonical v-prefixed form makes the bare 0.3.0 order +// exactly like v0.3.0 and lets semver order the whole tag set, which is valid +// Go semantic-version syntax once the prefix is present. +func normalize(version string) string { + if strings.hasPrefix(version, "v") { + return version + } + return "v" + version +} + +compareVer (a, b) => { + return semver.Compare(normalize(a.Version), normalize(b.Version)) +} From 5ae8263bae94c7eb59adaca317074da7a0b28520 Mon Sep 17 00:00:00 2001 From: MeteorsLiu <17515813+MeteorsLiu@users.noreply.github.com> Date: Tue, 4 Aug 2026 06:33:04 +0000 Subject: [PATCH 4/5] recp/cglm: lower fromVer to v0.8.0 with pkg-config fallback v0.8.0 and v0.8.1 use the same CMake build, options, and GNUInstallDirs layout as v0.8.5 but do not install a cglm.pc file (added at v0.8.2). Lower fromVer to v0.8.0 (renaming the version dir) and make the metadata step fall back to hand-built consumer flags (-I -L -lcglm -lm) when pkg-config cannot resolve cglm, so the pre-.pc tags are covered. onTest already derives its flags from the install layout, so it needs no change. --- recp/cglm/{v0.8.5 => v0.8.0}/Cglm_llar.gox | 30 ++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) rename recp/cglm/{v0.8.5 => v0.8.0}/Cglm_llar.gox (70%) diff --git a/recp/cglm/v0.8.5/Cglm_llar.gox b/recp/cglm/v0.8.0/Cglm_llar.gox similarity index 70% rename from recp/cglm/v0.8.5/Cglm_llar.gox rename to recp/cglm/v0.8.0/Cglm_llar.gox index 67fcb78..7a79d00 100644 --- a/recp/cglm/v0.8.5/Cglm_llar.gox +++ b/recp/cglm/v0.8.0/Cglm_llar.gox @@ -30,11 +30,13 @@ int main(void) { id "recp/cglm" -fromVer "v0.8.5" +fromVer "v0.8.0" // cglm is an optimized C99 math library. Its CMake build produces a single -// `cglm` library from `src/`, installs public headers under `include/cglm`, -// and generates a `cglm.pc` pkg-config file. +// `cglm` library from `src/` and installs public headers under `include/cglm`. +// A `cglm.pc` pkg-config file is installed from v0.8.2 onward; v0.8.0 and +// v0.8.1 ship the same CMake build and install layout but no `.pc`, so the +// metadata step falls back to hand-built flags for that range. // // Options mirror the meaningful choices of the Conan Center recipe: // - shared: build the shared library (ON) instead of the static one (OFF). @@ -65,16 +67,28 @@ onBuild ctx => { c.build c.install - // Derive consumer flags from the installed pkg-config file so metadata - // stays synchronized with the actual build (e.g. -lm on Linux/FreeBSD). + // Prefer the installed pkg-config file so metadata stays synchronized with + // the actual build (e.g. -lm on Linux/FreeBSD). v0.8.2+ install `cglm.pc`; + // v0.8.0 and v0.8.1 do not, so fall back to hand-built flags derived from + // the install layout when pkg-config cannot resolve cglm. c.use installDir capout => { exec "pkg-config", "--cflags", "--libs", "cglm" } - if lastErr != nil { - panic lastErr + if lastErr == nil { + ctx.setMetadata strings.trimSpace(output) + return + } + + // No usable `cglm.pc`: the CMake install still produces libcglm under + // /lib and headers under /include, matching the + // consumer flags the test uses. + flags := []string{ + "-I" + filepath.join(installDir, "include"), + "-L" + filepath.join(installDir, "lib"), + "-lcglm", "-lm", } - ctx.setMetadata strings.trimSpace(output) + ctx.setMetadata strings.join(flags, " ") } onTest ctx => { From 91c07917601876255515dc4caf0565600adb988f Mon Sep 17 00:00:00 2001 From: MeteorsLiu <17515813+MeteorsLiu@users.noreply.github.com> Date: Tue, 4 Aug 2026 08:37:44 +0000 Subject: [PATCH 5/5] recp/cglm: lower fromVer to v0.7.2 v0.7.2 is the first cglm tag with a CMakeLists, and its build contract (the CGLM_SHARED/CGLM_STATIC/CGLM_USE_TEST options, the cglm library under lib, headers under include/cglm) is functionally equivalent to v0.8.0's. The layout mechanics shift mid-range (hardcoded lib/ + INSTALL(DIRECTORY include/) at v0.7.2..v0.7.4, GNUInstallDirs from v0.7.6), but the net installed layout is identical and none of the range ships cglm.pc. The pkg-config fallback added for v0.8.0/v0.8.1 already covers the whole v0.7.2..v0.8.1 range, so lowering fromVer needs only the directory rename plus comment updates. onTest derives its flags from the install layout and needs no change. --- recp/cglm/{v0.8.0 => v0.7.2}/Cglm_llar.gox | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) rename recp/cglm/{v0.8.0 => v0.7.2}/Cglm_llar.gox (84%) diff --git a/recp/cglm/v0.8.0/Cglm_llar.gox b/recp/cglm/v0.7.2/Cglm_llar.gox similarity index 84% rename from recp/cglm/v0.8.0/Cglm_llar.gox rename to recp/cglm/v0.7.2/Cglm_llar.gox index 7a79d00..8593a66 100644 --- a/recp/cglm/v0.8.0/Cglm_llar.gox +++ b/recp/cglm/v0.7.2/Cglm_llar.gox @@ -30,13 +30,17 @@ int main(void) { id "recp/cglm" -fromVer "v0.8.0" +fromVer "v0.7.2" // cglm is an optimized C99 math library. Its CMake build produces a single // `cglm` library from `src/` and installs public headers under `include/cglm`. -// A `cglm.pc` pkg-config file is installed from v0.8.2 onward; v0.8.0 and -// v0.8.1 ship the same CMake build and install layout but no `.pc`, so the -// metadata step falls back to hand-built flags for that range. +// This build contract (the CGLM_SHARED/CGLM_STATIC/CGLM_USE_TEST options, the +// `cglm` library installed under `lib`, and headers under `include/cglm`) is +// stable from v0.7.2 — the first tag with a CMakeLists — onward. +// +// A `cglm.pc` pkg-config file is only installed from v0.8.2; v0.7.2..v0.8.1 +// ship the same build and install layout but no `.pc`, so the metadata step +// falls back to hand-built flags for that range. // // Options mirror the meaningful choices of the Conan Center recipe: // - shared: build the shared library (ON) instead of the static one (OFF). @@ -69,8 +73,8 @@ onBuild ctx => { // Prefer the installed pkg-config file so metadata stays synchronized with // the actual build (e.g. -lm on Linux/FreeBSD). v0.8.2+ install `cglm.pc`; - // v0.8.0 and v0.8.1 do not, so fall back to hand-built flags derived from - // the install layout when pkg-config cannot resolve cglm. + // v0.7.2..v0.8.1 do not, so fall back to hand-built flags derived from the + // install layout when pkg-config cannot resolve cglm. c.use installDir capout => { exec "pkg-config", "--cflags", "--libs", "cglm"