mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Implement lazy-loaded libcurl
- Uses `dlopen` to load libcurl at runtime for better portability. - Replaces the FETCH_AVAILABLE macro with download_available() check. - Provides descriptive error messages when libcurl is missing.
This commit is contained in:
committed by
Christoffer Lerno
parent
c5d7a03859
commit
de8a733c77
@@ -129,9 +129,6 @@ if(C3_USE_MIMALLOC)
|
|||||||
)
|
)
|
||||||
FetchContent_MakeAvailable(mimalloc)
|
FetchContent_MakeAvailable(mimalloc)
|
||||||
endif()
|
endif()
|
||||||
if (NOT WIN32)
|
|
||||||
find_package(CURL)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
find_package(Git QUIET)
|
find_package(Git QUIET)
|
||||||
if(C3_USE_TB AND GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
if(C3_USE_TB AND GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git")
|
||||||
@@ -606,12 +603,11 @@ if(MINGW)
|
|||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--stack,8388608")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CURL_FOUND)
|
if (NOT WIN32)
|
||||||
target_link_libraries(c3c ${CURL_LIBRARIES})
|
# For dlopen support
|
||||||
target_include_directories(c3c PRIVATE ${CURL_INCLUDE_DIRS})
|
if (CMAKE_DL_LIBS)
|
||||||
target_compile_definitions(c3c PUBLIC CURL_FOUND=1)
|
target_link_libraries(c3c ${CMAKE_DL_LIBS})
|
||||||
else()
|
endif()
|
||||||
target_compile_definitions(c3c PUBLIC CURL_FOUND=0)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -259,9 +259,7 @@ static void project_usage()
|
|||||||
PRINTF("Project Subcommands:");
|
PRINTF("Project Subcommands:");
|
||||||
print_cmd("view", "view the current projects structure.");
|
print_cmd("view", "view the current projects structure.");
|
||||||
print_cmd("add-target <name> <target_type> [sources...]", "add a new target to the project.");
|
print_cmd("add-target <name> <target_type> [sources...]", "add a new target to the project.");
|
||||||
#if FETCH_AVAILABLE
|
print_cmd("fetch", "fetch missing project libraries.");
|
||||||
print_cmd("fetch", "fetch missing project libraries.");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void project_view_usage()
|
static void project_view_usage()
|
||||||
|
|||||||
@@ -268,9 +268,14 @@ static void view_target(BuildParseContext context, JSONObject *target, bool verb
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#if FETCH_AVAILABLE
|
|
||||||
void fetch_project(BuildOptions* options)
|
void fetch_project(BuildOptions* options)
|
||||||
{
|
{
|
||||||
|
if (!download_available())
|
||||||
|
{
|
||||||
|
error_exit("The 'project fetch' command requires libcurl to download dependencies.\n"
|
||||||
|
"Please ensure libcurl is installed on your system.");
|
||||||
|
}
|
||||||
if (!file_exists(PROJECT_JSON5) && !file_exists(PROJECT_JSON))
|
if (!file_exists(PROJECT_JSON5) && !file_exists(PROJECT_JSON))
|
||||||
{
|
{
|
||||||
error_exit("Failed: no project file found.");
|
error_exit("Failed: no project file found.");
|
||||||
@@ -343,12 +348,7 @@ void fetch_project(BuildOptions* options)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void fetch_project(BuildOptions* options)
|
|
||||||
{
|
|
||||||
error_exit("Error: project fetch only available when compiled with cURL.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void add_libraries_to_project_file(const char** libs, const char* target_name) {
|
void add_libraries_to_project_file(const char** libs, const char* target_name) {
|
||||||
|
|||||||
@@ -966,7 +966,7 @@ bool use_ansi(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FETCH_AVAILABLE
|
|
||||||
const char * vendor_fetch_single(const char* lib, const char* path)
|
const char * vendor_fetch_single(const char* lib, const char* path)
|
||||||
{
|
{
|
||||||
const char *resource = str_printf("/c3lang/vendor/releases/download/latest/%s.c3l", lib);
|
const char *resource = str_printf("/c3lang/vendor/releases/download/latest/%s.c3l", lib);
|
||||||
@@ -993,6 +993,11 @@ void update_progress_bar(const char* lib, int current_step, int total_steps)
|
|||||||
|
|
||||||
void vendor_fetch(BuildOptions *options)
|
void vendor_fetch(BuildOptions *options)
|
||||||
{
|
{
|
||||||
|
if (!download_available())
|
||||||
|
{
|
||||||
|
error_exit("The 'vendor-fetch' command requires libcurl to download libraries.\n"
|
||||||
|
"Please ensure libcurl is installed on your system.");
|
||||||
|
}
|
||||||
bool ansi = use_ansi();
|
bool ansi = use_ansi();
|
||||||
|
|
||||||
if (str_eq(options->path, DEFAULT_PATH))
|
if (str_eq(options->path, DEFAULT_PATH))
|
||||||
@@ -1061,12 +1066,7 @@ void vendor_fetch(BuildOptions *options)
|
|||||||
|
|
||||||
if (ansi) printf("\033[32mFetching complete.\033[0m\t\t\n");
|
if (ansi) printf("\033[32mFetching complete.\033[0m\t\t\n");
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void vendor_fetch(BuildOptions *options)
|
|
||||||
{
|
|
||||||
error_exit("Error: vendor-fetch only available when compiled with cURL.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void print_syntax(BuildOptions *options)
|
void print_syntax(BuildOptions *options)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -54,11 +54,6 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if CURL_FOUND || PLATFORM_WINDOWS
|
|
||||||
#define FETCH_AVAILABLE 1
|
|
||||||
#else
|
|
||||||
#define FETCH_AVAILABLE 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define IS_GCC 0
|
#define IS_GCC 0
|
||||||
#define IS_CLANG 0
|
#define IS_CLANG 0
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ static void closedir(DIR *dir)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FETCH_AVAILABLE
|
|
||||||
|
|
||||||
static int version_compare(const char *v1, const char *v2)
|
static int version_compare(const char *v1, const char *v2)
|
||||||
{
|
{
|
||||||
@@ -509,6 +509,13 @@ static bool check_license(JSONObject *rj1_channel_items, bool accept_all)
|
|||||||
|
|
||||||
void fetch_msvc(BuildOptions *options)
|
void fetch_msvc(BuildOptions *options)
|
||||||
{
|
{
|
||||||
|
if (!download_available())
|
||||||
|
{
|
||||||
|
error_exit("Failed to find Windows SDK.\n"
|
||||||
|
"Windows applications cannot be cross-compiled without it.\n"
|
||||||
|
"To download the SDK automatically, please ensure libcurl is installed.\n"
|
||||||
|
"Alternatively, provide the SDK path manually using --winsdk.");
|
||||||
|
}
|
||||||
verbose_level = options->verbosity_level;
|
verbose_level = options->verbosity_level;
|
||||||
const char *tmp_dir_base = dir_make_temp_dir();
|
const char *tmp_dir_base = dir_make_temp_dir();
|
||||||
if (!tmp_dir_base) error_exit("Failed to create temp directory");
|
if (!tmp_dir_base) error_exit("Failed to create temp directory");
|
||||||
@@ -749,13 +756,5 @@ void fetch_msvc(BuildOptions *options)
|
|||||||
|
|
||||||
if (verbose_level == 0) file_delete_dir(tmp_dir_base);
|
if (verbose_level == 0) file_delete_dir(tmp_dir_base);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void fetch_msvc(BuildOptions *options)
|
|
||||||
{
|
|
||||||
error_exit("Failed to find Windows SDK.\n"
|
|
||||||
"Windows applications cannot be cross-compiled without it.\n"
|
|
||||||
"This build of c3c lacks cURL support and cannot download the SDK automatically.\n"
|
|
||||||
"Please provide the SDK path manually using --winsdk.");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|||||||
118
src/utils/http.c
118
src/utils/http.c
@@ -105,8 +105,84 @@ END:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif CURL_FOUND
|
bool download_available(void)
|
||||||
#include <curl/curl.h>
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif PLATFORM_POSIX
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
typedef void CURL;
|
||||||
|
typedef int CURLcode;
|
||||||
|
typedef int CURLoption;
|
||||||
|
|
||||||
|
#define CURLE_OK 0
|
||||||
|
#define CURLOPT_URL 10002
|
||||||
|
#define CURLOPT_FOLLOWLOCATION 52
|
||||||
|
#define CURLOPT_VERBOSE 41
|
||||||
|
#define CURLOPT_NOPROGRESS 43
|
||||||
|
#define CURLOPT_FAILONERROR 45
|
||||||
|
#define CURLOPT_WRITEFUNCTION 20011
|
||||||
|
#define CURLOPT_WRITEDATA 10001
|
||||||
|
#define CURLOPT_CAINFO 10065
|
||||||
|
|
||||||
|
static void *libcurl = NULL;
|
||||||
|
static CURL* (*ptr_curl_easy_init)(void);
|
||||||
|
static CURLcode (*ptr_curl_easy_setopt)(CURL *, CURLoption, ...);
|
||||||
|
static CURLcode (*ptr_curl_easy_perform)(CURL *);
|
||||||
|
static void (*ptr_curl_easy_cleanup)(CURL *);
|
||||||
|
static const char* (*ptr_curl_easy_strerror)(CURLcode);
|
||||||
|
|
||||||
|
static bool load_curl(void)
|
||||||
|
{
|
||||||
|
if (libcurl) return true;
|
||||||
|
const char *names[] = {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
"libcurl.4.dylib",
|
||||||
|
"libcurl.dylib",
|
||||||
|
"/usr/lib/libcurl.4.dylib",
|
||||||
|
"/usr/lib/libcurl.dylib",
|
||||||
|
"/opt/homebrew/lib/libcurl.dylib",
|
||||||
|
"/usr/local/lib/libcurl.dylib"
|
||||||
|
#else
|
||||||
|
"libcurl.so.4",
|
||||||
|
"libcurl.so",
|
||||||
|
"libcurl.so.3",
|
||||||
|
"libcurl-gnutls.so.4",
|
||||||
|
"libcurl-nss.so.4"
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(names) / sizeof(names[0]); i++)
|
||||||
|
{
|
||||||
|
libcurl = dlopen(names[i], RTLD_LAZY);
|
||||||
|
if (libcurl) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!libcurl) return false;
|
||||||
|
|
||||||
|
ptr_curl_easy_init = dlsym(libcurl, "curl_easy_init");
|
||||||
|
ptr_curl_easy_setopt = dlsym(libcurl, "curl_easy_setopt");
|
||||||
|
ptr_curl_easy_perform = dlsym(libcurl, "curl_easy_perform");
|
||||||
|
ptr_curl_easy_cleanup = dlsym(libcurl, "curl_easy_cleanup");
|
||||||
|
ptr_curl_easy_strerror = dlsym(libcurl, "curl_easy_strerror");
|
||||||
|
|
||||||
|
if (!ptr_curl_easy_init || !ptr_curl_easy_setopt || !ptr_curl_easy_perform || !ptr_curl_easy_cleanup || !ptr_curl_easy_strerror)
|
||||||
|
{
|
||||||
|
dlclose(libcurl);
|
||||||
|
libcurl = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool download_available(void)
|
||||||
|
{
|
||||||
|
return load_curl();
|
||||||
|
}
|
||||||
|
|
||||||
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
|
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
|
||||||
{
|
{
|
||||||
@@ -115,35 +191,43 @@ static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
|
|||||||
|
|
||||||
const char *download_file(const char *url, const char *resource, const char *file_path)
|
const char *download_file(const char *url, const char *resource, const char *file_path)
|
||||||
{
|
{
|
||||||
CURL *curl_handle = curl_easy_init();
|
if (!load_curl())
|
||||||
if (!curl_handle) error_exit("Could not initialize cURL subsystem.");
|
{
|
||||||
|
return "This build of c3c lacks cURL support and cannot download files automatically.\n"
|
||||||
|
"Please ensure libcurl is installed on your system.";
|
||||||
|
}
|
||||||
|
|
||||||
|
CURL *curl_handle = ptr_curl_easy_init();
|
||||||
|
if (!curl_handle) return "Could not initialize cURL subsystem.";
|
||||||
|
|
||||||
FILE *file = fopen(file_path, "w+b");
|
FILE *file = fopen(file_path, "w+b");
|
||||||
if (!file)
|
if (!file)
|
||||||
{
|
{
|
||||||
curl_easy_cleanup(curl_handle);
|
ptr_curl_easy_cleanup(curl_handle);
|
||||||
return str_printf("Failed to open file '%s' for output", file_path);
|
return str_printf("Failed to open file '%s' for output", file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *total_url = str_printf("%s%s", url, resource);
|
const char *total_url = str_printf("%s%s", url, resource);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_URL, total_url);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_URL, total_url);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0L);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0L);
|
||||||
// Enable this later
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1L);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1L);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
|
ptr_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, file);
|
||||||
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, file);
|
|
||||||
CURLcode result = curl_easy_perform(curl_handle);
|
CURLcode result = ptr_curl_easy_perform(curl_handle);
|
||||||
if (result != CURLE_OK)
|
if (result != CURLE_OK)
|
||||||
{
|
{
|
||||||
fclose(file);
|
fclose(file);
|
||||||
remove(file_path);
|
remove(file_path);
|
||||||
const char *err_msg = str_dup(curl_easy_strerror(result));
|
const char *err_msg = str_dup(ptr_curl_easy_strerror(result));
|
||||||
curl_easy_cleanup(curl_handle);
|
ptr_curl_easy_cleanup(curl_handle);
|
||||||
return err_msg;
|
return err_msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(file);
|
fclose(file);
|
||||||
curl_easy_cleanup(curl_handle);
|
ptr_curl_easy_cleanup(curl_handle);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,8 @@
|
|||||||
#include "intrin.h"
|
#include "intrin.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if FETCH_AVAILABLE
|
|
||||||
const char *download_file(const char *url, const char *resource, const char *file_path);
|
const char *download_file(const char *url, const char *resource, const char *file_path);
|
||||||
#endif
|
bool download_available(void);
|
||||||
|
|
||||||
#define ELEMENTLEN(x) (sizeof(x) / sizeof(x[0]))
|
#define ELEMENTLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||||
extern const char *compiler_exe_name;
|
extern const char *compiler_exe_name;
|
||||||
|
|||||||
Reference in New Issue
Block a user