feat(pdm): pdm-control LibraryPath + InstallDir

Two optional pdm-control fields:
- LibraryPath: true/false  — when true, pmm writes the package's lib dir to
  ~/.bashrc LD_LIBRARY_PATH so shared libs installed by PMM are found at runtime
  (per-package opt-in; default false so plain tools don't pollute the env).
- InstallDir: <subdir>     — install the package to ~/.pmm/root/<subdir> (its
  bin goes to <subdir>/bin and is added to PATH; <subdir>/lib is what
  LibraryPath points at).

Also ensure the target dir exists before tar -C. Updated ppdm.md tutorial.
这个提交包含在:
JGZYES
2026-09-06 16:04:47 +08:00
父节点 26cb5f89f4
当前提交 bc666bcb4c
修改 4 个文件,包含 64 行新增8 行删除
+25
查看文件
@@ -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 <root>/bin executable. Windows doesn't
+27 -8
查看文件
@@ -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 <subdir>/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 <home>/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;
+6
查看文件
@@ -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);
+6
查看文件
@@ -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