diff --git a/src/pdm.c b/src/pdm.c index bd75bf4..ff7fedb 100644 --- a/src/pdm.c +++ b/src/pdm.c @@ -540,6 +540,23 @@ int pdm_install_file(const char *pdmfile) { chdir_restore(); remove(tmpname); return -1; } + /* pdm-control knobs: LibraryPath (auto-add lib dir to LD_LIBRARY_PATH) and + * InstallDir (optional install subdir under the PMM root). */ + pmm_libpath_wanted = 0; + pmm_install_subdir[0] = 0; + char *libp = control_get(ctl, "LibraryPath"); + if (libp && libp[0]) { pmm_libpath_wanted = (strcmp(libp, "true") == 0 || strcmp(libp, "1") == 0); free(libp); } + char *inst = control_get(ctl, "InstallDir"); + if (inst && *inst) { + /* keep it relative & safe (no .., no leading /) */ + size_t il = strlen(inst); + if (il >= sizeof(pmm_install_subdir)) il = sizeof(pmm_install_subdir) - 1; + memcpy(pmm_install_subdir, inst, il); pmm_install_subdir[il] = 0; + for (char *q = pmm_install_subdir; *q; q++) if (*q == '\\') *q = '/'; + if (pmm_install_subdir[0] == '/' || strstr(pmm_install_subdir, "..")) pmm_install_subdir[0] = 0; + free(inst); + } + /* reject an install that would conflict with a package already present */ char *confl = control_get(ctl, "Conflicts"); if (confl && *confl && any_installed_conflict(confl)) { @@ -551,6 +568,12 @@ int pdm_install_file(const char *pdmfile) { /* extract data into root (relative target: cwd is already the pm dir) */ const char *tgt = flat ? "." : "root"; + char tgtbuf[1400]; + if (!flat && pmm_install_subdir[0]) { + snprintf(tgtbuf, sizeof(tgtbuf), "root/%s", pmm_install_subdir); + tgt = tgtbuf; + } + mkdir_p(tgt); /* ensure the target dir exists before -C */ /* If the package is pmm itself, its exe is the currently running binary and * Windows/locked images can't be overwritten by tar. Move it aside first so * the new binary can be written; restore on failure. */ @@ -622,6 +645,8 @@ int pdm_install_file(const char *pdmfile) { } pmm_add_to_path(); /* auto-put PMM dirs (e.g. root/nodejs) on PATH */ + pmm_libpath_wanted = 0; /* don't leak the LibraryPath/InstallDir to later installs */ + pmm_install_subdir[0] = 0; #ifndef _WIN32 /* On Linux/macOS, mark anything in /bin executable. Windows doesn't diff --git a/src/pmm.c b/src/pmm.c index 425a36b..da64d5e 100644 --- a/src/pmm.c +++ b/src/pmm.c @@ -113,6 +113,10 @@ static const char *home_dir(void) { static char g_drive[4] = ""; /* "D", or "" = use home */ static char g_base_path[1024] = ""; /* exact install base, or "" */ +/* Set by pdm_install_file from pdm-control (LibraryPath / InstallDir). */ +int pmm_libpath_wanted = 0; +char pmm_install_subdir[256] = ""; + static const char *drive_state_path(char *buf, size_t size) { snprintf(buf, size, "%s/.pmm/install-drive", home_dir()); return buf; @@ -366,6 +370,17 @@ void pmm_add_to_path(void) { } #endif + /* A package may declare an install subdir (pdm-control InstallDir): also put + * its /bin on PATH if it holds executables. */ + if (pmm_install_subdir[0]) { + char subbin[1400]; + snprintf(subbin, sizeof(subbin), "%s/%s/bin", base, pmm_install_subdir); + if (dir_has_exec(subbin)) add_path_candidate(list, &n, 160, subbin); + char subcmd[1400]; + snprintf(subcmd, sizeof(subcmd), "%s/%s/cmd", base, pmm_install_subdir); + if (dir_has_exec(subcmd)) add_path_candidate(list, &n, 160, subcmd); + } + /* read current user PATH */ char cur[16384] = ""; #ifdef _WIN32 @@ -435,14 +450,18 @@ void pmm_add_to_path(void) { if (f) { fprintf(f, "\n# PMM PATH\n"); for (int i = 0; i < n; i++) if (list[i][0]) fprintf(f, "export PATH=\"%s:$PATH\"\n", list[i]); - /* Shared libraries installed by PMM live under /root/lib; - * make them findable by dynamically-linked tools automatically. */ - fprintf(f, "\n# PMM shared library path\n"); - if (pmm_flat_mode()) - fprintf(f, "export LD_LIBRARY_PATH=\"%s/lib:%LD_LIBRARY_PATH\"\n", home); - else - fprintf(f, "export LD_LIBRARY_PATH=\"%s/root/lib:%s/root/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH\"\n", - home, home); + /* If the package opted in (pdm-control: LibraryPath=true), make its + * lib dir findable by dynamically-linked tools automatically. */ + if (pmm_libpath_wanted) { + char libdir[1400]; + if (pmm_install_subdir[0]) + snprintf(libdir, sizeof(libdir), "%s/%s/lib", base, pmm_install_subdir); + else + snprintf(libdir, sizeof(libdir), "%s/lib", base); + fprintf(f, "\n# PMM shared library path\n"); + fprintf(f, "export LD_LIBRARY_PATH=\"%s:%s/x86_64-linux-gnu:$LD_LIBRARY_PATH\"\n", + libdir, libdir); + } fclose(f); } (void)she; diff --git a/src/pmm.h b/src/pmm.h index e322582..42e2523 100644 --- a/src/pmm.h +++ b/src/pmm.h @@ -9,6 +9,12 @@ * On Windows persists via the user registry PATH; on Unix appends to shell rc. */ void pmm_add_to_path(void); +/* Set by the .pdm installer from pdm-control (LibraryPath/InstallDir) before + * calling pmm_add_to_path: whether to export the package's lib dir on + * LD_LIBRARY_PATH, and an optional install subdir under the PMM root. */ +extern int pmm_libpath_wanted; +extern char pmm_install_subdir[256]; + /* Set the install location by drive letter ("D" -> D:\.pmm). An empty string * clears back to the user-home default. Persisted across runs. */ void pmm_set_install_drive(const char *letter); diff --git a/web/docs/md/ppdm.md b/web/docs/md/ppdm.md index f9ffabd..5e4e31b 100644 --- a/web/docs/md/ppdm.md +++ b/web/docs/md/ppdm.md @@ -78,8 +78,14 @@ Version: 1.0.0 Architecture: linux Description: My app Maintainer: you@mail.com +# 可选: +# LibraryPath: true # 装到 ~/.pmm/root 后,自动把本包 lib/ 加入 LD_LIBRARY_PATH(新 shell 生效) +# InstallDir: tools/myapp # 把本包装到 ~/.pmm/root/tools/myapp (bin -> .../bin, lib -> .../lib) ``` +> `LibraryPath` 默认 `false`(不加);`true` 时 pmm 会在 `~/.bashrc` 写入本包 lib 目录的 +> `LD_LIBRARY_PATH`。`InstallDir` 可把包装到 `~/.pmm/root/<子目录>`,该目录下的 `bin` 也会进 PATH。 + 打包: ```bash