build: finish cross-platform release tooling

This commit is contained in:
WHC
2026-10-10 16:21:00 +08:00
parent 9bf7707912
commit 50abcf1a91
29 changed files with 973 additions and 230 deletions
+61 -29
View File
@@ -22,43 +22,75 @@
#define ERRBODY_MAX 4096
#define LLM_MAX_RETRIES 3
/* Point libcurl at a CA bundle on Windows.
static int ca_file_ok(const char *path) {
if (!path || !path[0])
return 0;
FILE *f = fopen(path, "rb");
if (!f)
return 0;
fclose(f);
return 1;
}
/* Point libcurl at a CA bundle.
*
* An OpenSSL-based libcurl keeps the path it was built with -- MSYS2's is
* "/mingw64/etc/ssl/certs/ca-bundle.crt", which resolves to nothing once the
* binary runs outside an MSYS2 shell, and that build ignores CURL_CA_BUNDLE.
* Every HTTPS request then dies with CURLE_SSL_CACERT_BADFILE (77).
* libcurl keeps the bundle path it was built with. On Windows an OpenSSL
* build carries MSYS2's "/mingw64/etc/ssl/certs/ca-bundle.crt"; the static
* Linux release is built on one distro and runs on all of them, whose bundles
* live in different places. A path that does not exist fails every HTTPS
* request with CURLE_SSL_CACERT_BADFILE (77).
*
* Order: $CST_CA_BUNDLE, then ca-bundle.crt beside the executable. If neither
* exists nothing is set, so a libcurl linked against Schannel (the Windows
* certificate store) behaves exactly as before. */
static void llm_apply_ca_bundle(CURL *curl) {
#if defined(_WIN32)
* Order: $CST_CA_BUNDLE; on Windows ca-bundle.crt beside the executable (if
* absent nothing is set, so Schannel uses the certificate store); elsewhere
* $SSL_CERT_FILE, libcurl's own default if that file exists, then the usual
* distro locations. Decided once per process. */
void cst_curl_apply_ca(void *curl) {
static char ca[OS_PATH_MAX];
static int checked;
if (!checked) {
checked = 1;
static atomic_int state; /* 0 unchecked, 1 checking, 2 done */
int expect = 0;
if (atomic_compare_exchange_strong(&state, &expect, 1)) {
const char *env = getenv("CST_CA_BUNDLE");
if (env && env[0]) {
if (ca_file_ok(env)) {
snprintf(ca, sizeof(ca), "%s", env);
} else {
char dir[OS_PATH_MAX];
if (os_exe_dir(dir, sizeof(dir)) == 0)
os_path_join(ca, sizeof(ca), dir, "ca-bundle.crt");
}
if (ca[0]) {
FILE *f = fopen(ca, "rb");
if (f)
fclose(f);
#if defined(_WIN32)
char dir[OS_PATH_MAX], p[OS_PATH_MAX];
if (os_exe_dir(dir, sizeof(dir)) == 0 &&
os_path_join(p, sizeof(p), dir, "ca-bundle.crt") == 0 &&
ca_file_ok(p))
snprintf(ca, sizeof(ca), "%s", p);
#else
static const char *const known[] = {
"/etc/ssl/certs/ca-certificates.crt", /* Debian, Ubuntu, Arch, Alpine */
"/etc/pki/tls/certs/ca-bundle.crt", /* Fedora, RHEL */
"/etc/ssl/cert.pem", /* macOS, BSD, Alpine */
"/etc/ssl/ca-bundle.pem", /* openSUSE */
"/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem",
};
const char *pick = NULL;
const char *sslenv = getenv("SSL_CERT_FILE");
const curl_version_info_data *vi = curl_version_info(CURLVERSION_NOW);
if (ca_file_ok(sslenv))
pick = sslenv;
else if (vi && ca_file_ok(vi->cainfo))
pick = NULL; /* libcurl's built-in default already works */
else
ca[0] = '\0';
for (size_t i = 0; i < sizeof(known) / sizeof(known[0]); i++)
if (ca_file_ok(known[i])) {
pick = known[i];
break;
}
if (pick)
snprintf(ca, sizeof(ca), "%s", pick);
#endif
}
atomic_store(&state, 2);
} else {
while (atomic_load(&state) != 2)
;
}
if (ca[0])
curl_easy_setopt(curl, CURLOPT_CAINFO, ca);
#else
(void)curl;
#endif
curl_easy_setopt((CURL *)curl, CURLOPT_CAINFO, ca);
}
#include "cst_attach.h"
@@ -988,7 +1020,7 @@ int cst_llm_chat_stream(const cst_llm_request_t *req, char *err,
ret = -1;
break;
}
llm_apply_ca_bundle(curl);
cst_curl_apply_ca(curl);
sse_reset(&s);
s.curl = curl;
if (rec_dir && rec_dir[0]) {
@@ -1233,7 +1265,7 @@ int cst_llm_list_models_meta(const char *api_base, const char *api_key,
snprintf(err, err_sz, "curl init failed");
return -1;
}
llm_apply_ca_bundle(curl);
cst_curl_apply_ca(curl);
char url[1024];
size_t bl = strlen(api_base);
while (bl && api_base[bl - 1] == '/')