~lattis/muon

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
8

[PATCH 0/8] python: miscellaneous improvements

Details
Message ID
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com>
DKIM signature
pass
Download raw message
Hi,

This is a series of patches that fixes some bugs in the Python module
implementation along with implementing the method `get_install_dir`.

tinyjson's `json_create()` failed with out of memory while running
tests. This is the first time I've noticed a failure here, so for now I
have bumped the allowed max fields to 2048. I have tested it on
archlinuxarm (Rpi4) only.

I'm planning to import some of meson's Python test suite after
implementing `install_sources` (ongoing), so I haven't added any test
cases for `get_install_dir` yet.

Thanks!

Seedo Paul (8):
  add module specific options for python
  mod/python: accept kwarg 'pure' for find_installation
  tinyjson: bump max fields to 2048
  mod/python: fix logic when discovering python_installation
  find_installation: use `python3` as fallback when cmd is empty
  mod/python: store install_paths from introspection
  string: add missing include
  mod/python: implement `get_install_dir`

 include/lang/object.h                 |   2 +
 include/lang/string.h                 |   2 +
 src/external/tinyjson.c               |   2 +-
 src/functions/modules/python.c        | 136 +++++++++++++++++++++++---
 src/lang/object.c                     |   3 +
 src/meson_opts.c                      |   6 +-
 src/script/global_options.meson       |   6 ++
 tests/project/muon/python/meson.build |   6 ++
 8 files changed, 144 insertions(+), 19 deletions(-)


base-commit: 20cafd21421d417b8964723b4c06cfa28d857814
-- 
2.45.0

[PATCH 1/8] add module specific options for python

Details
Message ID
<D193KP4PZG3C.4G55BPPWPDSC@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +10 -2
---
 src/meson_opts.c                | 6 ++++--
 src/script/global_options.meson | 6 ++++++
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/meson_opts.c b/src/meson_opts.c
index e543b2f5..0f4a19f3 100644
--- a/src/meson_opts.c
+++ b/src/meson_opts.c
@@ -425,8 +425,10 @@ translate_meson_opts_setup(struct workspace *wk, char *argv[], uint32_t argc, st
		{ "pkgconfig.relocatable", .ignore = true },
		{ "prefer-static", false, "prefer_static" },
		{ "python.install-env", true, .ignore = true },
		{ "python.platlibdir", true, .ignore = true },
		{ "python.purelibdir", true, .ignore = true },
		{ "python.bytecompile", true, .ignore = true },
		{ "python.platlibdir", true },
		{ "python.purelibdir", true },
		{ "python.allow_limited_api", true, .ignore = true },
		{ "stdsplit", false, "stdsplit" },
		{ "strip", false, "strip" },
		{ "unity", true, "unity" },
diff --git a/src/script/global_options.meson b/src/script/global_options.meson
index 7d6cfd80..f5525d6c 100644
--- a/src/script/global_options.meson
+++ b/src/script/global_options.meson
@@ -144,6 +144,12 @@ option('cpp_rtti', type: 'boolean', value: true) # TODO
option('cpp_thread_count', type: 'integer', value: 4, min: 0) # TODO
option('cpp_winlibs', type: 'array', value: []) # TODO

# Python specific options
option('python.bytecompile', type: 'integer', value: 0, min: -1, max: 2)
option('python.purelibdir', type: 'string', value: '')
option('python.platlibdir', type: 'string', value: '')
option('python.allow_limited_api', type: 'boolean', value: true)

# muon-specific options.  These are safe from being overridden because meson
# forbids . in an opiton name

-- 
2.45.0

[PATCH 2/8] mod/python: accept kwarg 'pure' for find_installation

Details
Message ID
<D193KP4PZQKW.3S0MLH86XX341@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +11 -0
---
 include/lang/object.h          | 1 +
 src/functions/modules/python.c | 9 +++++++++
 src/lang/object.c              | 1 +
 3 files changed, 11 insertions(+)

diff --git a/include/lang/object.h b/include/lang/object.h
index a904ce87..4eda958d 100644
--- a/include/lang/object.h
+++ b/include/lang/object.h
@@ -323,6 +323,7 @@ struct obj_external_program {
struct obj_python_installation {
	obj prog;

	bool pure;
	obj language_version;
	obj sysconfig_paths;
	obj sysconfig_vars;
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index c0f56287..731dc39b 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -6,6 +6,7 @@
#include "coerce.h"
#include "compat.h"

#include "lang/object.h"
#include <string.h>

#include "embedded.h"
@@ -104,15 +105,22 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
		kw_required,
		kw_disabler,
		kw_modules,
		kw_pure,
	};
	struct args_kw akw[] = { [kw_required] = { "required", tc_required_kw },
		[kw_disabler] = { "disabler", obj_bool },
		[kw_modules] = { "modules", TYPE_TAG_LISTIFY | obj_string },
		[kw_pure] = { "pure", obj_bool },
		0 };
	if (!pop_args(wk, an, akw)) {
		return false;
	}

	bool pure = false;
	if (akw[kw_pure].set) {
		pure = get_obj_bool(wk, akw[kw_pure].val);
	}

	enum requirement_type requirement;
	if (!coerce_requirement(wk, &akw[kw_required], &requirement)) {
		return false;
@@ -162,6 +170,7 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)

	make_obj(wk, res, obj_python_installation);
	struct obj_python_installation *python = get_obj_python_installation(wk, *res);
	python->pure = pure;
	make_obj(wk, &python->prog, obj_external_program);
	struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
	ep->found = found;
diff --git a/src/lang/object.c b/src/lang/object.c
index 94b18351..ea9f0455 100644
--- a/src/lang/object.c
+++ b/src/lang/object.c
@@ -1969,6 +1969,7 @@ obj_to_s_opts(struct workspace *wk, obj o, struct sbuf *sb, struct obj_to_s_opts
		obj_to_s_opts(wk, py->prog, sb, opts);

		if (get_obj_external_program(wk, py->prog)->found) {
			sbuf_pushf(wk, sb, ", pure: %s", py->pure ? "true" : "false");
			sbuf_pushf(wk, sb, ", language_version: %s", get_cstr(wk, py->language_version));
			sbuf_pushs(wk, sb, ", sysconfig_paths: ");
			obj_to_s_opts(wk, py->sysconfig_paths, sb, opts);
-- 
2.45.0

[PATCH 4/8] mod/python: fix logic when discovering python_installation

Details
Message ID
<D193KP4Q0953.1I3ULR581KDQ9@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +31 -15
Earlier, the following line threw an error saying "failed to introspect
python interpreter":

py = import('python')
py_nonexisting = import('a_nonexisting_python_cmd', required: false)

The fix is to return early when the interpreter is not found, without
introspecting the (non-existing) interpreter.
---
 src/functions/modules/python.c        | 40 +++++++++++++++++----------
 tests/project/muon/python/meson.build |  6 ++++
 2 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 731dc39b..ba9c3da2 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -97,6 +97,26 @@ iterate_required_module_list(struct workspace *wk, void *ctx, obj val)
	return ir_err;
}

static bool
build_python_installation(struct workspace *wk, obj self, obj *res, struct sbuf cmd_path, bool found, bool pure)
{
	make_obj(wk, res, obj_python_installation);
	struct obj_python_installation *python = get_obj_python_installation(wk, *res);
	python->pure = pure;
	make_obj(wk, &python->prog, obj_external_program);
	struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
	ep->found = found;
	make_obj(wk, &ep->cmd_array, obj_array);
	obj_array_push(wk, ep->cmd_array, sbuf_into_str(wk, &cmd_path));

	if (found && !introspect_python_interpreter(wk, cmd_path.buf, python)) {
		vm_error(wk, "failed to introspect python");
		return false;
	}

	return true;
}

static bool
func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
{
@@ -145,6 +165,10 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
		return true;
	}

	if (!found) {
		return build_python_installation(wk, self, res, cmd_path, found, pure);
	}

	if (akw[kw_modules].set && found) {
		bool all_present = obj_array_foreach(wk,
			akw[kw_modules].val,
@@ -168,21 +192,7 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)
		}
	}

	make_obj(wk, res, obj_python_installation);
	struct obj_python_installation *python = get_obj_python_installation(wk, *res);
	python->pure = pure;
	make_obj(wk, &python->prog, obj_external_program);
	struct obj_external_program *ep = get_obj_external_program(wk, python->prog);
	ep->found = found;
	make_obj(wk, &ep->cmd_array, obj_array);
	obj_array_push(wk, ep->cmd_array, sbuf_into_str(wk, &cmd_path));

	if (!introspect_python_interpreter(wk, cmd_path.buf, python)) {
		vm_error(wk, "failed to introspect python");
		return false;
	}

	return true;
	return build_python_installation(wk, self, res, cmd_path, found, pure);
}

static bool
diff --git a/tests/project/muon/python/meson.build b/tests/project/muon/python/meson.build
index 34088022..fab0f045 100644
--- a/tests/project/muon/python/meson.build
+++ b/tests/project/muon/python/meson.build
@@ -10,6 +10,12 @@ if py.language_version().version_compare('< 3.6')
    error('Invalid Python version, only >= 3.6 is supported.')
endif

py_nonexisting = import('nonexisting_python_b075e5a', required: false)

if py_nonexisting.found()
    error('Python installation found that is unlikely to exist.')
endif

# kwargs
pymod_with_modules = py_mod.find_installation(
    'python3',
-- 
2.45.0

[PATCH 3/8] tinyjson: bump max fields to 2048

Details
Message ID
<D193KP4Q0040.83BA6TQ24FJ2@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +1 -1
Python introspection failed recently in my tests due to out of memory,
so double the maximum permitted fields.
---
 src/external/tinyjson.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/external/tinyjson.c b/src/external/tinyjson.c
index 36b82ed9..9250b634 100644
--- a/src/external/tinyjson.c
+++ b/src/external/tinyjson.c
@@ -13,7 +13,7 @@
#include "lang/string.h"
#include "log.h"

#define TINYJSON_MAX_FIELDS 1024
#define TINYJSON_MAX_FIELDS 2048

static bool
build_dict_from_json(struct workspace *wk, const json_t *json, obj *res)
-- 
2.45.0

[PATCH 5/8] find_installation: use `python3` as fallback when cmd is empty

Details
Message ID
<D193KP4Q0HXY.2QW05NRCCZEVQ@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +4 -1
Otherwise, muon hits an assertion and crashes.
---
 src/functions/modules/python.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index ba9c3da2..643cacfb 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -150,7 +150,10 @@ func_module_python_find_installation(struct workspace *wk, obj self, obj *res)

	const char *cmd = "python3";
	if (an[0].set) {
		cmd = get_cstr(wk, an[0].val);
		const char *pycmd = get_cstr(wk, an[0].val);
		if (pycmd && *pycmd) {
			cmd = pycmd;
		}
	}

	SBUF(cmd_path);
-- 
2.45.0

[PATCH 6/8] mod/python: store install_paths from introspection

Details
Message ID
<D193KP4Q0QDZ.2UAGXFALJ847@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +8 -0
---
 include/lang/object.h          | 1 +
 src/functions/modules/python.c | 5 +++++
 src/lang/object.c              | 2 ++
 3 files changed, 8 insertions(+)

diff --git a/include/lang/object.h b/include/lang/object.h
index 4eda958d..241245ce 100644
--- a/include/lang/object.h
+++ b/include/lang/object.h
@@ -327,6 +327,7 @@ struct obj_python_installation {
	obj language_version;
	obj sysconfig_paths;
	obj sysconfig_vars;
	obj install_paths;
};

enum run_result_flags {
diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 643cacfb..4e9400a5 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -52,6 +52,11 @@ introspect_python_interpreter(struct workspace *wk, const char *path, struct obj
		success = false;
		goto end;
	}

	if (!obj_dict_index_str(wk, res_introspect, "install_paths", &python->install_paths)) {
		success = false;
		goto end;
	}
end:
	run_cmd_ctx_destroy(&cmd_ctx);
	return success;
diff --git a/src/lang/object.c b/src/lang/object.c
index ea9f0455..9a609dfa 100644
--- a/src/lang/object.c
+++ b/src/lang/object.c
@@ -1975,6 +1975,8 @@ obj_to_s_opts(struct workspace *wk, obj o, struct sbuf *sb, struct obj_to_s_opts
			obj_to_s_opts(wk, py->sysconfig_paths, sb, opts);
			sbuf_pushs(wk, sb, ", sysconfig_vars: ");
			obj_to_s_opts(wk, py->sysconfig_vars, sb, opts);
			sbuf_pushs(wk, sb, ", install_paths: ");
			obj_to_s_opts(wk, py->install_paths, sb, opts);
		}

		sbuf_pushs(wk, sb, ">");
-- 
2.45.0

[PATCH 7/8] string: add missing include

Details
Message ID
<D193KP4Q0YE1.2F7F59I3GABH5@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +2 -0
fixes #123
---
 include/lang/string.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/lang/string.h b/include/lang/string.h
index 07d4351f..2ee16644 100644
--- a/include/lang/string.h
+++ b/include/lang/string.h
@@ -8,6 +8,8 @@

#include "compat.h"

#include <string.h>

#include "lang/object.h"

struct workspace;
-- 
2.45.0

[PATCH 8/8] mod/python: implement `get_install_dir`

Details
Message ID
<D193KP4Q16TI.KAX53FHRA253@gmail.com>
In-Reply-To
<D193KP4PYFQQ.1WLCJWOJIRE90@gmail.com> (view parent)
DKIM signature
pass
Download raw message
Patch: +78 -1
---
 src/functions/modules/python.c | 79 +++++++++++++++++++++++++++++++++-
 1 file changed, 78 insertions(+), 1 deletion(-)

diff --git a/src/functions/modules/python.c b/src/functions/modules/python.c
index 4e9400a5..7c092be9 100644
--- a/src/functions/modules/python.c
+++ b/src/functions/modules/python.c
@@ -7,12 +7,14 @@
#include "compat.h"

#include "lang/object.h"
#include <string.h>
#include "options.h"
#include "platform/path.h"

#include "embedded.h"
#include "external/tinyjson.h"
#include "functions/external_program.h"
#include "functions/modules/python.h"
#include "install.h"
#include "lang/typecheck.h"
#include "platform/filesystem.h"
#include "platform/run_cmd.h"
@@ -320,6 +322,80 @@ func_python_installation_has_var(struct workspace *wk, obj self, obj *res)
	return true;
}

static bool
get_install_dir(struct workspace *wk, obj self, bool pure, const char *subdir, obj *res)
{
	SBUF(installdir);

	obj prefix;
	get_option_value(wk, current_project(wk), "prefix", &prefix);

	struct obj_python_installation *py = get_obj_python_installation(wk, self);

	if (pure) {
		obj puredir;
		get_option_value(wk, current_project(wk), "python.purelibdir", &puredir);
		if (!str_eql(get_str(wk, puredir), &WKSTR(""))) {
			path_push(wk, &installdir, get_cstr(wk, puredir));
		} else {
			if (!obj_dict_index_str(wk, py->install_paths, "purelib", &puredir)) {
				return false;
			}
			path_join_absolute(wk, &installdir, get_cstr(wk, prefix), get_cstr(wk, puredir));
		}
	} else {
		obj platdir;
		get_option_value(wk, current_project(wk), "python.platlibdir", &platdir);
		if (!str_eql(get_str(wk, platdir), &WKSTR(""))) {
			path_push(wk, &installdir, get_cstr(wk, platdir));
		} else {
			if (!obj_dict_index_str(wk, py->install_paths, "platlib", &platdir)) {
				return false;
			}
			path_join_absolute(wk, &installdir, get_cstr(wk, prefix), get_cstr(wk, platdir));
		}
	}

	if (subdir) {
		path_push(wk, &installdir, subdir);
	}

	*res = sbuf_into_str(wk, &installdir);

	return true;
}

static bool
func_python_installation_get_install_dir(struct workspace *wk, obj self, obj *res)
{
	enum kwargs {
		kw_pure,
		kw_subdir,
	};
	struct args_kw akw[] = {
		[kw_pure] = { "pure", obj_bool },
		[kw_subdir] = { "subdir", obj_string },
		0
	};

	if (!pop_args(wk, NULL, akw)) {
		return false;
	}

	struct obj_python_installation *py = get_obj_python_installation(wk, self);
	bool pure = py->pure;
	if (akw[kw_pure].set) {
		pure = get_obj_bool(wk, akw[kw_pure].val);
	}

	const char *subdir = NULL;
	if (akw[kw_subdir].set) {
		subdir = get_cstr(wk, akw[kw_subdir].val);
	}

	return get_install_dir(wk, self, pure, subdir, res);
}

static obj
python_self_transform(struct workspace *wk, obj self)
{
@@ -349,6 +425,7 @@ const struct func_impl impl_tbl_module_python3[] = {

struct func_impl impl_tbl_python_installation[] = {
	[ARRAY_LEN(impl_tbl_external_program) - 1] = { "get_path", func_python_installation_get_path, tc_string },
	{ "get_install_dir", func_python_installation_get_install_dir, tc_string },
	{ "get_variable", func_python_installation_get_var, tc_string },
	{ "has_path", func_python_installation_has_path, tc_bool },
	{ "has_variable", func_python_installation_has_var, tc_bool },
-- 
2.45.0
Reply to thread Export thread (mbox)