diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index f6a126c..859af21 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -27,6 +27,7 @@ edi_build_provider_make.c \ edi_build_provider_cmake.c \ edi_build_provider_cargo.c \ edi_build_provider_python.c \ +edi_build_provider_meson.c \ edi_build_provider.c \ edi_builder.c \ edi_create.c \ diff --git a/src/lib/edi_build_provider.c b/src/lib/edi_build_provider.c index 520ac31..60ddb79 100644 --- a/src/lib/edi_build_provider.c +++ b/src/lib/edi_build_provider.c @@ -11,6 +11,7 @@ extern Edi_Build_Provider _edi_build_provider_make; extern Edi_Build_Provider _edi_build_provider_cmake; extern Edi_Build_Provider _edi_build_provider_cargo; extern Edi_Build_Provider _edi_build_provider_python; +extern Edi_Build_Provider _edi_build_provider_meson; EAPI Edi_Build_Provider *edi_build_provider_for_project_get() { @@ -26,11 +27,12 @@ EAPI Edi_Build_Provider *edi_build_provider_for_project_path_get(const char *pat return &_edi_build_provider_make; if (_edi_build_provider_cmake.path_supported_is(path)) return &_edi_build_provider_cmake; - if (_edi_build_provider_cargo.path_supported_is(path)) return &_edi_build_provider_cargo; if (_edi_build_provider_python.path_supported_is(path)) return &_edi_build_provider_python; + if (_edi_build_provider_meson.path_supported_is(path)) + return &_edi_build_provider_meson; return NULL; } @@ -45,6 +47,8 @@ EAPI Edi_Build_Provider *edi_build_provider_for_id_get(const char *id) return &_edi_build_provider_cargo; if (!strcmp("python", id)) return &_edi_build_provider_python; + if (!strcmp("meson", id)) + return &_edi_build_provider_meson; return NULL; } diff --git a/src/lib/edi_build_provider_meson.c b/src/lib/edi_build_provider_meson.c new file mode 100644 index 0000000..b6bc591 --- /dev/null +++ b/src/lib/edi_build_provider_meson.c @@ -0,0 +1,174 @@ +#ifdef HAVE_CONFIG +# include "config.h" +#endif + +#include +#include +#include +#include + +#include "Edi.h" + +#include "edi_private.h" + +typedef struct { + char *basedir; + char *builddir; + char *fulldir; /* basedir + builddir */ +} Meson_Data; + +static Eina_Bool +_meson_project_supported(const char *path) +{ + return edi_path_relative_exists(path, "meson.build"); +} + +static Meson_Data * +_meson_data_get(void) +{ + // FIXME: I hate static globals + // FIXME: this needs to be freed on project change / shutdown! + static Meson_Data *md = NULL; + + if (md) return md; + + md = calloc(1, sizeof(*md)); + md->basedir = strdup(edi_project_get()); + md->builddir = strdup("build"); // FIXME: "build" dir needs to be user-defined + md->fulldir = edi_path_append(md->basedir, md->builddir); + return md; +} + +static Eina_Bool +_meson_configured_check(const char *dir) +{ + const char *build_ninja; + + build_ninja = eina_slstr_steal_new(edi_path_append(dir, "build.ninja")); + if (ecore_file_exists(build_ninja)) + return EINA_TRUE; + + return EINA_FALSE; +} + +static Eina_Bool +_meson_file_hidden_is(const char *file) +{ + if (!file || strlen(file) == 0) + return EINA_FALSE; + + static const char *hidden_exts[] = { + ".o", ".so", ".lo", + ".ninja", ".ninja", ".ninja_deps", ".ninja_log", + "compile_commands.json", "meson-logs", "meson-private", "@exe" + }; + + if (ecore_file_is_dir(file) && _meson_configured_check(file)) + return EINA_TRUE; + + for (size_t k = 0; k < EINA_C_ARRAY_LENGTH(hidden_exts); k++) + if (eina_str_has_extension(file, hidden_exts[k])) + return EINA_TRUE; + + return EINA_FALSE; +} + +static Eina_Bool +_meson_project_runnable_is(const char *path) +{ + return ecore_file_can_exec(path); +} + +static Ecore_Exe * +_meson_ninja_do(Meson_Data *md, const char *arg) +{ + const char *cmd; + + cmd = eina_slstr_printf("ninja -C %s %s", md->fulldir, arg ?: ""); + return ecore_exe_pipe_run(cmd, + ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ | + ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR | + ECORE_EXE_PIPE_WRITE /*| ECORE_EXE_USE_SH*/, md); +} + +static Eina_Bool +_meson_prepare_end(void *data, int evtype EINA_UNUSED, void *evinfo) +{ + Meson_Data *me = data; + Ecore_Exe_Event_Del *ev = evinfo; + + if (!ev->exe) return ECORE_CALLBACK_RENEW; + if (ecore_exe_data_get(ev->exe) != me) return ECORE_CALLBACK_RENEW; + + _meson_ninja_do(me, NULL); + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +_meson_prepare(Meson_Data *md) +{ + const char *cmd; + Ecore_Exe *exe; + + if (_meson_configured_check(md->fulldir)) return EINA_TRUE; + if (chdir(md->basedir) != 0) return EINA_FALSE; + + cmd = eina_slstr_printf("meson %s", md->builddir); + exe = ecore_exe_pipe_run(cmd, + ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ | + ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR | + ECORE_EXE_PIPE_WRITE /*| ECORE_EXE_USE_SH*/, md); + + if (!exe) return EINA_FALSE; + ecore_event_handler_add(ECORE_EXE_EVENT_DEL, _meson_prepare_end, md); + + return EINA_FALSE; +} + +static void +_meson_build(void) +{ + Meson_Data *md = _meson_data_get(); + + if (!_meson_prepare(md)) + return; + + _meson_ninja_do(md, NULL); +} + +static void +_meson_test(void) +{ + ERR("Edi doesn't support test with Meson/Ninja!"); +} + +static void +_meson_run(const char *path, const char *args) +{ + Meson_Data *md = _meson_data_get(); + const char *cmd; + + if (chdir(edi_project_get()) != 0) + ERR("Could not chdir"); + + if (args) cmd = eina_slstr_printf("%s %s", path, args); + else cmd = path; + ecore_exe_pipe_run(cmd, + ECORE_EXE_PIPE_READ_LINE_BUFFERED | ECORE_EXE_PIPE_READ | + ECORE_EXE_PIPE_ERROR_LINE_BUFFERED | ECORE_EXE_PIPE_ERROR | + ECORE_EXE_PIPE_WRITE /*| ECORE_EXE_USE_SH*/, md); +} + +static void +_meson_clean(void) +{ + Meson_Data *md = _meson_data_get(); + + if (!_meson_configured_check(md->fulldir)) return; + _meson_ninja_do(md, "clean"); +} + +Edi_Build_Provider _edi_build_provider_meson = + {"meson", _meson_project_supported, _meson_file_hidden_is, + _meson_project_runnable_is, _meson_build, _meson_test, + _meson_run, _meson_clean};