~lattis/muon

5a7234d256d50c8d030a5feddb6b979c3a8fc749 — Stone Tickle a month ago 241efa5
fix custom target implicit dependencies

before, custom_target naiively assumed that the first element of command
was the only implicit dependency, which not only caused builds to fail
if said element was not an absolute path (ex. 'sh'), but also failed to
capture real implicit dependencies.
M include/functions/default/custom_target.h => include/functions/default/custom_target.h +1 -2
@@ 3,7 3,6 @@
#include "functions/common.h"

bool process_custom_target_commandline(struct workspace *wk, uint32_t err_node,
	uint32_t arr, uint32_t input, uint32_t output, uint32_t depfile,
	uint32_t *res);
	obj arr, obj input, obj output, obj depfile, obj depends, obj *res);
bool func_custom_target(struct workspace *wk, uint32_t _, uint32_t args_node, uint32_t *obj);
#endif

M include/lang/object.h => include/lang/object.h +1 -0
@@ 128,6 128,7 @@ struct obj {
			obj args; // obj_array
			obj input; // obj_array
			obj output; // obj_array
			obj depends; // obj_array
			enum custom_target_flags flags;
		} custom_target;
		struct {

M src/backend/ninja/custom_target.c => src/backend/ninja/custom_target.c +2 -7
@@ 67,12 67,7 @@ ninja_write_custom_tgt(struct workspace *wk, const struct project *proj, obj tgt
		return ir_err;
	}

	uint32_t cmd;
	obj_array_index(wk, tgt->dat.custom_target.args, 0, &cmd);
	char cmd_escaped[PATH_MAX];
	if (!ninja_escape(cmd_escaped, PATH_MAX, get_cstr(wk, cmd))) {
		return ir_err;
	}
	obj depends = join_args_ninja(wk, tgt->dat.custom_target.depends);

	obj_array_extend(wk, cmdline, tgt_args);



@@ 85,7 80,7 @@ ninja_write_custom_tgt(struct workspace *wk, const struct project *proj, obj tgt
		" DESCRIPTION = %s\n\n",
		get_cstr(wk, outputs),
		get_cstr(wk, inputs),
		cmd_escaped,
		get_cstr(wk, depends),
		get_cstr(wk, cmdline),
		get_cstr(wk, cmdline)
		);

M src/coerce.c => src/coerce.c +1 -1
@@ 48,7 48,7 @@ coerce_executable(struct workspace *wk, uint32_t node, uint32_t val, uint32_t *r

	switch ((obj = get_obj(wk, val))->type) {
	case obj_file:
		str = get_obj(wk, val)->dat.str;
		str = get_obj(wk, val)->dat.file;
		break;
	case obj_build_target: {
		char tmp1[PATH_MAX], dest[PATH_MAX];

M src/functions/default/configure_file.c => src/functions/default/configure_file.c +4 -2
@@ 265,7 265,7 @@ generate_config(struct workspace *wk, uint32_t dict, uint32_t node, uint32_t out

static bool
configure_file_with_command(struct workspace *wk, uint32_t node,
	uint32_t command, uint32_t input, uint32_t out_path, uint32_t depfile,
	obj command, obj input, obj out_path, obj depfile,
	bool capture)
{
	uint32_t args, output_arr;


@@ 277,8 277,10 @@ configure_file_with_command(struct workspace *wk, uint32_t node,
		obj_array_push(wk, output_arr, f);
	}

	obj depends; // used only for the call below :(
	make_obj(wk, &depends, obj_array);
	if (!process_custom_target_commandline(wk, node, command, input,
		output_arr, depfile, &args)) {
		output_arr, depfile, depends, &args)) {
		return false;
	}


M src/functions/default/custom_target.c => src/functions/default/custom_target.c +31 -32
@@ 12,8 12,9 @@
#include "platform/filesystem.h"

struct custom_target_cmd_fmt_ctx {
	uint32_t arr, err_node;
	uint32_t input, output, depfile;
	uint32_t err_node;
	obj arr, input, output, depfile, depends;
	bool skip_depends;
};

static bool


@@ 148,57 149,65 @@ format_cmd_arg_cb(struct workspace *wk, uint32_t node, void *_ctx, const struct 
}

static enum iteration_result
custom_target_cmd_fmt_iter(struct workspace *wk, void *_ctx, uint32_t val)
custom_target_cmd_fmt_iter(struct workspace *wk, void *_ctx, obj val)
{
	struct custom_target_cmd_fmt_ctx *ctx = _ctx;

	uint32_t str;
	struct obj *obj;
	obj ss;
	struct obj *o = get_obj(wk, val);

	switch ((obj = get_obj(wk, val))->type) {
	switch (o->type) {
	case obj_build_target:
	case obj_external_program:
	case obj_file:
		if (!coerce_executable(wk, ctx->err_node, val, &str)) {
		if (!coerce_executable(wk, ctx->err_node, val, &ss)) {
			return ir_err;
		}

		if (!ctx->skip_depends) {
			obj_fprintf(wk, log_file(), "%o | pushing: %o\n", val, ss);
			obj_array_push(wk, ctx->depends, ss);
		}
		break;
	case obj_string: {
		if (strcmp(get_cstr(wk, val), "@INPUT@") == 0) {
			ctx->skip_depends = true;
			if (!obj_array_foreach(wk, ctx->input, ctx, custom_target_cmd_fmt_iter)) {
				return ir_err;
			}
			ctx->skip_depends = false;
			return ir_cont;
		} else if (strcmp(get_cstr(wk, val), "@OUTPUT@") == 0) {
			ctx->skip_depends = true;
			if (!obj_array_foreach(wk, ctx->output, ctx, custom_target_cmd_fmt_iter)) {
				return ir_err;
			}
			ctx->skip_depends = false;
			return ir_cont;
		}

		uint32_t s;
		str s;
		if (!string_format(wk, ctx->err_node, get_obj(wk, val)->dat.str,
			&s, ctx, format_cmd_arg_cb)) {
			return ir_err;
		}
		make_obj(wk, &str, obj_string)->dat.str = s;
		make_obj(wk, &ss, obj_string)->dat.str = s;
		break;
	}
	default:
		interp_error(wk, ctx->err_node, "unable to coerce '%s' to string", obj_type_to_s(obj->type));
		interp_error(wk, ctx->err_node, "unable to coerce %o to string", val);
		return ir_err;
	}

	assert(get_obj(wk, str)->type == obj_string);
	assert(get_obj(wk, ss)->type == obj_string);

	obj_array_push(wk, ctx->arr, str);
	obj_array_push(wk, ctx->arr, ss);
	return ir_cont;
}

bool
process_custom_target_commandline(struct workspace *wk, uint32_t err_node,
	uint32_t arr, uint32_t input, uint32_t output, uint32_t depfile,
	uint32_t *res)
	obj arr, obj input, obj output, obj depfile, obj depends, obj *res)
{
	make_obj(wk, res, obj_array);
	struct custom_target_cmd_fmt_ctx ctx = {


@@ 207,6 216,7 @@ process_custom_target_commandline(struct workspace *wk, uint32_t err_node,
		.input = input,
		.output = output,
		.depfile = depfile,
		.depends = depends,
	};

	if (!obj_array_foreach_flat(wk, arr, &ctx, custom_target_cmd_fmt_iter)) {


@@ 218,22 228,6 @@ process_custom_target_commandline(struct workspace *wk, uint32_t err_node,
		return false;
	}

	obj cmd;
	obj_array_index(wk, *res, 0, &cmd);

	/* TODO: this needs to be handle differentiation between commands that
	   are build targets */
	/* if (!path_is_absolute(get_cstr(wk, cmd))) { */
	/* 	const char *cmd_path; */
	/* 	if (!fs_find_cmd(get_cstr(wk, cmd), &cmd_path)) { */
	/* 		interp_error(wk, err_node, "command '%s' not found", */
	/* 			get_cstr(wk, cmd)); */
	/* 		return false; */
	/* 	} */

	/* 	obj_array_set(wk, *res, 0, make_str(wk, cmd_path)); */
	/* } */

	return true;
}



@@ 301,7 295,6 @@ format_cmd_output_cb(struct workspace *wk, uint32_t node, void *_ctx, const stru
	return format_cb_found;
}


static enum iteration_result
custom_command_output_format_iter(struct workspace *wk, void *_ctx, obj v)
{


@@ 381,11 374,16 @@ func_custom_target(struct workspace *wk, obj _, uint32_t args_node, obj *res)
		return false;
	}

	obj depends;
	make_obj(wk, &depends, obj_array);
	obj_fprintf(wk, log_file(), "command: %o\n", akw[kw_command].val);
	if (!process_custom_target_commandline(wk, akw[kw_command].node,
		akw[kw_command].val, input, output, akw[kw_depfile].val, &args)) {
		akw[kw_command].val, input, output, akw[kw_depfile].val, depends, &args)) {
		return false;
	}

	obj_fprintf(wk, log_file(), "depends: %o\n", depends);

	if (akw[kw_capture].set && get_obj(wk, akw[kw_capture].val)->dat.boolean) {
		flags |= custom_target_capture;
	}


@@ 396,6 394,7 @@ func_custom_target(struct workspace *wk, obj _, uint32_t args_node, obj *res)
	tgt->dat.custom_target.args = args;
	tgt->dat.custom_target.input = input;
	tgt->dat.custom_target.output = output;
	tgt->dat.custom_target.depends = depends;
	tgt->dat.custom_target.flags = flags;

	if ((akw[kw_install].set && get_obj(wk, akw[kw_install].val)->dat.boolean)