~lattis/muon

5ef61811175d065dfdda1e34fe2b63905b900c15 — Stone Tickle 5 months ago 0106c97
improve find_library and pkgconfig lib resolution
M bootstrap.sh => bootstrap.sh +0 -1
@@ 92,7 92,6 @@ cat \
	src/machine_file.c \
	src/main.c \
	src/opts.c \
	src/platform/dirs.c \
	src/platform/filesystem.c \
	src/platform/mem.c \
	src/platform/path.c \

M include/backend/common_args.h => include/backend/common_args.h +9 -3
@@ 6,10 6,16 @@
bool setup_compiler_args(struct workspace *wk, const struct obj *tgt,
	const struct project *proj, obj include_dirs, obj dep_args,
	obj *joined_args);

struct setup_linker_args_ctx {
	enum linker_type linker;
	enum compiler_language link_lang;
	struct dep_args_ctx *args;
	obj implicit_deps;
};

void setup_linker_args(struct workspace *wk, const struct project *proj,
	const struct obj *tgt, enum linker_type linker,
	enum compiler_language link_lang,
	obj rpaths, obj link_args, obj link_with);
	const struct obj *tgt, struct setup_linker_args_ctx *ctx);

struct setup_compiler_args_includes_ctx {
	obj args;

M include/compilers.h => include/compilers.h +1 -0
@@ 77,6 77,7 @@ struct compiler {

struct linker {
	struct {
		compiler_get_arg_func_1s lib;
		compiler_get_arg_func_0 as_needed;
		compiler_get_arg_func_0 no_undefined;
		compiler_get_arg_func_0 start_group;

M include/external/libpkgconf.h => include/external/libpkgconf.h +1 -1
@@ 7,7 7,7 @@

struct pkgconf_info {
	char version[MAX_VERSION_LEN + 1];
	uint32_t includes, libs;
	obj includes, libs, not_found_libs, link_args, compile_args;
};

extern const bool have_libpkgconf;

M include/functions/dependency.h => include/functions/dependency.h +6 -1
@@ 3,7 3,12 @@
#include "functions/common.h"

struct dep_args_ctx {
	obj compile_args, include_dirs, link_with, link_args, rpath;
	obj compile_args,
	    include_dirs,
	    link_with,
	    link_with_not_found,
	    link_args,
	    rpath;
	bool relativize, recursive;
};


M include/lang/object.h => include/lang/object.h +2 -0
@@ 161,6 161,7 @@ struct obj {
			obj name; // obj_string
			obj version; // obj_string
			obj link_with; // obj_array
			obj link_with_not_found; // obj_array
			obj link_args; // obj_array
			obj include_directories; // obj_array
			obj variables; // obj_dict


@@ 201,6 202,7 @@ struct obj {
		struct {
			obj name;
			obj ver;
			obj libdirs;
			enum compiler_type type;
			enum compiler_language lang;
		} compiler;

D include/platform/dirs.h => include/platform/dirs.h +0 -4
@@ 1,4 0,0 @@
#ifndef MUON_PLATFORM_DIRS_H
#define MUON_PLATFORM_DIRS_H
extern const char *libdirs[];
#endif

M src/backend/common_args.c => src/backend/common_args.c +38 -28
@@ 6,6 6,7 @@
#include "args.h"
#include "backend/common_args.h"
#include "functions/default/options.h"
#include "functions/dependency.h"
#include "log.h"
#include "platform/filesystem.h"
#include "platform/path.h"


@@ 287,17 288,12 @@ setup_compiler_args(struct workspace *wk, const struct obj *tgt,
	return true;
}

struct setup_linker_args_ctx {
	enum linker_type linker;
	obj link_args;
};

static enum iteration_result
process_rpath_iter(struct workspace *wk, void *_ctx, obj v)
{
	struct setup_linker_args_ctx *ctx = _ctx;

	push_args(wk, ctx->link_args, linkers[ctx->linker].args.rpath(get_cstr(wk, v)));
	push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.rpath(get_cstr(wk, v)));

	return ir_cont;
}


@@ 320,51 316,65 @@ setup_optional_b_args_linker(struct workspace *wk, const struct project *proj,
	return true;
}

static enum iteration_result
push_not_found_lib_iter(struct workspace *wk, void *_ctx, obj v)
{
	struct setup_linker_args_ctx *ctx = _ctx;

	push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.lib(get_cstr(wk, v)));
	return ir_cont;
}

void
setup_linker_args(struct workspace *wk, const struct project *proj,
	const struct obj *tgt, enum linker_type linker,
	enum compiler_language link_lang,
	obj rpaths, obj link_args, obj link_with)
	const struct obj *tgt, struct setup_linker_args_ctx *ctx)
{
	struct setup_linker_args_ctx ctx = {
		.linker = linker,
		.link_args = link_args,
	};
	obj link_with;
	obj_array_dedup(wk, ctx->args->link_with, &link_with);
	ctx->args->link_with = link_with;

	push_args(wk, link_args, linkers[linker].args.as_needed());
	push_args(wk, link_args, linkers[linker].args.no_undefined());
	obj link_with_not_found;
	obj_array_dedup(wk, ctx->args->link_with_not_found, &link_with_not_found);
	ctx->args->link_with_not_found = link_with_not_found;

	make_obj(wk, &ctx->implicit_deps, obj_array);

	push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.as_needed());
	push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.no_undefined());

	if (proj) {
		if (tgt->dat.tgt.flags & build_tgt_flag_export_dynamic) {
			push_args(wk, link_args, linkers[linker].args.export_dynamic());
			push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.export_dynamic());
		}

		setup_optional_b_args_linker(wk, proj, link_args, linker);
		setup_optional_b_args_linker(wk, proj, ctx->args->link_args, ctx->linker);

		/* global args */
		obj global_args, global_args_dup;
		if (obj_dict_geti(wk, wk->global_link_args, link_lang, &global_args)) {
		if (obj_dict_geti(wk, wk->global_link_args, ctx->link_lang, &global_args)) {
			obj_array_dup(wk, global_args, &global_args_dup);
			obj_array_extend(wk, link_args, global_args_dup);
			obj_array_extend(wk, ctx->args->link_args, global_args_dup);
		}

		/* project args */
		obj proj_args, proj_args_dup;
		if (obj_dict_geti(wk, proj->link_args, link_lang, &proj_args)) {
		if (obj_dict_geti(wk, proj->link_args, ctx->link_lang, &proj_args)) {
			obj_array_dup(wk, proj_args, &proj_args_dup);
			obj_array_extend(wk, link_args, proj_args_dup);
			obj_array_extend(wk, ctx->args->link_args, proj_args_dup);
		}
	}

	obj_array_foreach(wk, rpaths, &ctx, process_rpath_iter);
	obj_array_foreach(wk, ctx->args->rpath, ctx, process_rpath_iter);

	if (get_obj(wk, ctx->args->link_with)->dat.arr.len) {
		push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.start_group());

	if (get_obj(wk, link_with)->dat.arr.len) {
		push_args(wk, link_args, linkers[linker].args.start_group());
		obj dup;
		obj_array_dup(wk, ctx->args->link_with, &dup);
		obj_array_extend(wk, ctx->args->link_args, dup);

		obj arr;
		obj_array_dup(wk, link_with, &arr);
		obj_array_extend(wk, link_args, arr);
		obj_array_foreach(wk, ctx->args->link_with_not_found, ctx, push_not_found_lib_iter);

		push_args(wk, link_args, linkers[linker].args.end_group());
		push_args(wk, ctx->args->link_args, linkers[ctx->linker].args.end_group());
	}
}

M src/backend/ninja/build_target.c => src/backend/ninja/build_target.c +8 -6
@@ 285,15 285,17 @@ ninja_write_build_tgt(struct workspace *wk, const struct project *proj, obj tgt_

	obj implicit_deps = 0;
	if (tgt->dat.tgt.type == tgt_executable) {
		obj link_with;
		obj_array_dedup(wk, ctx.args.link_with, &link_with);
		struct setup_linker_args_ctx sctx = {
			.linker = linker,
			.link_lang = ctx.link_language,
			.args = &ctx.args
		};

		setup_linker_args(wk, ctx.proj, tgt, &sctx);

		if (get_obj(wk, ctx.args.link_with)->dat.arr.len) {
			implicit_deps = str_join(wk, make_str(wk, " | "), join_args_ninja(wk, link_with));
			implicit_deps = str_join(wk, make_str(wk, " | "), join_args_ninja(wk, ctx.args.link_with));
		}

		setup_linker_args(wk, ctx.proj, tgt, linker, ctx.link_language,
			ctx.args.rpath, ctx.args.link_args, link_with);
	}

	const char *linker_type, *link_args;

M src/compilers.c => src/compilers.c +70 -2
@@ 148,6 148,62 @@ detection_over:
	return true;
}

static bool
compiler_get_libdirs(struct workspace *wk, struct obj *comp)
{
	struct run_cmd_ctx cmd_ctx = { 0 };
	if (!run_cmd(&cmd_ctx, get_cstr(wk, comp->dat.compiler.name), (const char *[]){
		get_cstr(wk, comp->dat.compiler.name), "--print-search-dirs", NULL,
	}, NULL) || cmd_ctx.status) {
		goto done;
	}

	const char *key = "libraries: ";
	char *s, *e;
	bool beginning_of_line = true;
	for (s = cmd_ctx.out.buf; *s; ++s) {
		if (beginning_of_line && strncmp(s, key, strlen(key)) == 0) {
			s += strlen(key);
			if (*s == '=') {
				++s;
			}

			e = strchr(s, '\n');

			struct str str = {
				.s = s,
				.len = e ? (uint32_t)(e - s) : strlen(s),
			};

			comp->dat.compiler.libdirs = str_split(wk, &str, &WKSTR(":"));
			goto done;
		}

		beginning_of_line = *s == '\n';
	}

done:
	run_cmd_ctx_destroy(&cmd_ctx);

	if (!comp->dat.compiler.libdirs) {
		const char *libdirs[] = {
			"/usr/lib",
			"/usr/local/lib",
			"/lib",
			NULL
		};

		make_obj(wk, &comp->dat.compiler.libdirs, obj_array);

		uint32_t i;
		for (i = 0; libdirs[i]; ++i) {
			obj_array_push(wk, comp->dat.compiler.libdirs, make_str(wk, libdirs[i]));
		}
	}

	return true;
}

bool
compiler_detect(struct workspace *wk, uint32_t *comp, enum compiler_language lang)
{


@@ 174,7 230,9 @@ compiler_detect(struct workspace *wk, uint32_t *comp, enum compiler_language lan
			return false;
		}

		get_obj(wk, *comp)->dat.compiler.lang = lang;
		struct obj *compiler = get_obj(wk, *comp);
		compiler_get_libdirs(wk, compiler);
		compiler->dat.compiler.lang = lang;
		return true;
	default:
		assert(false);


@@ 483,6 541,15 @@ build_compilers(void)
}

static const struct args *
linker_posix_args_lib(const char *s)
{
	COMPILER_ARGS({ "-l", NULL });
	argv[1] = s;

	return &args;
}

static const struct args *
linker_gcc_args_as_needed(void)
{
	COMPILER_ARGS({ "-Wl,--as-needed" });


@@ 505,7 572,6 @@ linker_gcc_args_start_group(void)
	return &args;
}


static const struct args *
linker_gcc_args_end_group(void)
{


@@ 562,6 628,7 @@ build_linkers(void)
	/* linkers */
	struct linker empty = {
		.args = {
			.lib          = compiler_arg_empty_1s,
			.as_needed    = compiler_arg_empty_0,
			.no_undefined = compiler_arg_empty_0,
			.start_group  = compiler_arg_empty_0,


@@ 576,6 643,7 @@ build_linkers(void)
	};

	struct linker posix = empty;
	posix.args.lib = linker_posix_args_lib;

	struct linker gcc = posix;
	gcc.args.as_needed = linker_gcc_args_as_needed;

M src/external/libpkgconf.c => src/external/libpkgconf.c +14 -12
@@ 8,7 8,6 @@
#include "lang/object.h"
#include "lang/workspace.h"
#include "log.h"
#include "platform/dirs.h"
#include "platform/filesystem.h"
#include "platform/path.h"



@@ 23,7 22,7 @@ static bool init = false;
static bool
error_handler(const char *msg, const pkgconf_client_t *client, const void *data)
{
	/* log_plain("%s", msg); */
	L("libpkgconf: %s", msg);
	return true;
}



@@ 79,8 78,8 @@ struct pkgconf_lookup_ctx {
	apply_func apply_func;
	struct workspace *wk;
	struct pkgconf_info *info;
	uint32_t libdirs;
	uint32_t name;
	obj libdirs;
	obj name;
	bool is_static;
};



@@ 109,7 108,6 @@ check_lib_path(struct find_lib_path_ctx *ctx, const char *lib_path)
	uint32_t i;

	char name[PATH_MAX];

	for (i = 0; i < ext_count; ++i) {
		snprintf(name, PATH_MAX - 1, "lib%s%s", ctx->name, ext[ext_order[i]]);



@@ 209,14 207,15 @@ apply_and_collect(pkgconf_client_t *client, pkgconf_pkg_t *world, void *_ctx, in
					obj_array_push(ctx->wk, ctx->info->libs, str);
				}
			} else {
				LOG_E("library '%s' not found for dependency '%s'", frag->data, get_cstr(ctx->wk, ctx->name));
				return false;
				LOG_W("library '%s' not found for dependency '%s'", frag->data, get_cstr(ctx->wk, ctx->name));
				obj_array_push(ctx->wk, ctx->info->not_found_libs, make_str(ctx->wk, frag->data));
			}
			break;
		}
		default:
			if (frag->type) {
				L("skipping unknown pkgconf fragment: -%c '%s'", frag->type, frag->data);
				obj_array_push(ctx->wk, ctx->info->compile_args,
					make_strf(ctx->wk, "-%c%s", frag->type, frag->data));
			} else {
				L("skipping null pkgconf fragment: '%s'", frag->data);
			}


@@ 270,14 269,17 @@ muon_pkgconf_lookup(struct workspace *wk, uint32_t name, bool is_static, struct 
		goto ret;
	}

	make_obj(wk, &info->compile_args, obj_array);
	make_obj(wk, &info->link_args, obj_array);
	make_obj(wk, &info->includes, obj_array);
	make_obj(wk, &info->libs, obj_array);
	make_obj(wk, &info->not_found_libs, obj_array);
	make_obj(wk, &ctx.libdirs, obj_array);

	uint32_t i;
	for (i = 0; libdirs[i]; ++i) {
		obj_array_push(wk, ctx.libdirs, make_str(wk, libdirs[i]));
	}
	/* uint32_t i; */
	/* for (i = 0; libdirs[i]; ++i) { */
	/* 	obj_array_push(wk, ctx.libdirs, make_str(wk, libdirs[i])); */
	/* } */

	ctx.apply_func = pkgconf_pkg_libs;
	if (!pkgconf_queue_apply(&client, &pkgq, apply_and_collect, maxdepth, &ctx)) {

M src/functions/compiler.c => src/functions/compiler.c +51 -29
@@ 14,7 14,6 @@
#include "functions/dependency.h"
#include "lang/interpreter.h"
#include "log.h"
#include "platform/dirs.h"
#include "platform/filesystem.h"
#include "platform/path.h"
#include "platform/run_cmd.h"


@@ 114,8 113,13 @@ compiler_check(struct workspace *wk, struct compiler_check_opts *opts,
			return false;
		}

		setup_linker_args(wk, NULL, NULL, compilers[t].linker,
			comp->dat.compiler.lang, da_ctx.rpath, da_ctx.link_args, da_ctx.link_with);
		struct setup_linker_args_ctx sctx = {
			.linker = compilers[t].linker,
			.link_lang = comp->dat.compiler.lang,
			.args = &da_ctx
		};

		setup_linker_args(wk, NULL, NULL, &sctx);
		obj_array_extend(wk, compiler_args, da_ctx.link_args);
	}



@@ 986,8 990,38 @@ func_compiler_get_id(struct workspace *wk, uint32_t rcvr, uint32_t args_node, ui
	return true;
}

struct compiler_find_library_ctx {
	char path[PATH_MAX];
	obj lib_name;
	bool found;
};

static enum iteration_result
compiler_find_library_iter(struct workspace *wk, void *_ctx, obj libdir)
{
	struct compiler_find_library_ctx *ctx = _ctx;
	char lib[PATH_MAX];
	static const char *suf[] = { "so", "a", NULL };

	uint32_t i;
	for (i = 0; suf[i]; ++i) {
		snprintf(lib, PATH_MAX, "lib%s.%s", get_cstr(wk, ctx->lib_name), suf[i]);

		if (!path_join(ctx->path, PATH_MAX, get_cstr(wk, libdir), lib)) {
			return false;
		}

		if (fs_file_exists(ctx->path)) {
			ctx->found = true;
			return ir_done;
		}
	}

	return ir_cont;
}

static bool
func_compiler_find_library(struct workspace *wk, uint32_t _, uint32_t args_node, uint32_t *obj)
func_compiler_find_library(struct workspace *wk, obj rcvr, uint32_t args_node, obj *res)
{
	struct args_norm an[] = { { obj_string }, ARG_TYPE_NULL };
	enum kwargs {


@@ 1012,32 1046,20 @@ func_compiler_find_library(struct workspace *wk, uint32_t _, uint32_t args_node,
	}

	if (requirement == requirement_skip) {
		make_obj(wk, obj, obj_external_library)->dat.external_library.found = false;
		make_obj(wk, res, obj_external_library)->dat.external_library.found = false;
		return true;
	}

	bool found = false;
	char lib[PATH_MAX], path[PATH_MAX];
	const char *suf[] = { "so", "a", NULL };

	uint32_t i, j;
	for (i = 0; libdirs[i]; ++i) {
		for (j = 0; suf[j]; ++j) {
			snprintf(lib, PATH_MAX, "lib%s.%s", get_cstr(wk, an[0].val), suf[j]);

			if (!path_join(path, PATH_MAX, libdirs[i], lib)) {
				return false;
			}
	struct compiler_find_library_ctx ctx = {
		.lib_name = an[0].val
	};
	struct obj *comp = get_obj(wk, rcvr);

			if (fs_file_exists(path)) {
				found = true;
				goto done;
			}
		}
	if (!obj_array_foreach(wk, comp->dat.compiler.libdirs, &ctx, compiler_find_library_iter)) {
		return false;
	}

done:
	if (!found) {
	if (!ctx.found) {
		if (requirement == requirement_required) {
			interp_error(wk, an[0].node, "library not found");
			return false;


@@ 1045,15 1067,15 @@ done:

		LOG_W("library '%s' not found", get_cstr(wk, an[0].val));
		if (akw[kw_disabler].set && get_obj(wk, akw[kw_disabler].val)->dat.boolean) {
			*obj = disabler_id;
			*res = disabler_id;
		} else {
			make_obj(wk, obj, obj_external_library)->dat.external_library.found = false;
			make_obj(wk, res, obj_external_library)->dat.external_library.found = false;
		}
	} else {
		LOG_I("found library '%s' at '%s'", get_cstr(wk, an[0].val), path);
		struct obj *external_library = make_obj(wk, obj, obj_external_library);
		LOG_I("found library '%s' at '%s'", get_cstr(wk, an[0].val), ctx.path);
		struct obj *external_library = make_obj(wk, res, obj_external_library);
		external_library->dat.external_library.found = true;
		external_library->dat.external_library.full_path = make_str(wk, path);
		external_library->dat.external_library.full_path = make_str(wk, ctx.path);
	}

	return true;

M src/functions/default/dependency.c => src/functions/default/dependency.c +3 -0
@@ 129,7 129,10 @@ get_dependency_pkgconfig(struct workspace *wk, struct dep_lookup_ctx *ctx, bool 
	dep->dat.dep.version = ver_str;
	dep->dat.dep.flags |= dep_flag_found | dep_flag_pkg_config;
	dep->dat.dep.link_with = info.libs;
	dep->dat.dep.link_with_not_found = info.not_found_libs;
	dep->dat.dep.include_directories = info.includes;
	dep->dat.dep.compile_args = info.compile_args;
	dep->dat.dep.link_args = info.link_args;

	*found = true;
	return true;

M src/functions/dependency.c => src/functions/dependency.c +7 -0
@@ 154,6 154,12 @@ dep_args_iter(struct workspace *wk, void *_ctx, obj val)
			}
		}

		if (dep->dat.dep.link_with_not_found) {
			obj dup;
			obj_array_dup(wk, dep->dat.dep.link_with_not_found, &dup);
			obj_array_extend(wk, ctx->link_with_not_found, dup);
		}

		if (dep->dat.dep.include_directories) {
			if (!obj_array_foreach_flat(wk, dep->dat.dep.include_directories,
				_ctx, dep_args_includes_iter)) {


@@ 202,6 208,7 @@ dep_args_ctx_init(struct workspace *wk, struct dep_args_ctx *ctx)

	make_obj(wk, &ctx->include_dirs, obj_array);
	make_obj(wk, &ctx->link_with, obj_array);
	make_obj(wk, &ctx->link_with_not_found, obj_array);
	make_obj(wk, &ctx->link_args, obj_array);
	make_obj(wk, &ctx->compile_args, obj_array);
	make_obj(wk, &ctx->rpath, obj_array);

M src/meson.build => src/meson.build +0 -1
@@ 52,7 52,6 @@ src = (
        'lang/serial.c',
        'lang/string.c',
        'lang/workspace.c',
        'platform/dirs.c',
        'platform/filesystem.c',
        'platform/mem.c',
        'platform/path.c',

D src/platform/dirs.c => src/platform/dirs.c +0 -10
@@ 1,10 0,0 @@
#include "posix.h"

#include <stddef.h>

const char *libdirs[] = {
	"/usr/lib",
	"/usr/local/lib",
	"/lib",
	NULL
};