Skip to content

Commit

Permalink
fix rpaths
Browse files Browse the repository at this point in the history
  • Loading branch information
mxcl committed Jul 15, 2022
1 parent 59eea56 commit 08c7609
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 19 deletions.
8 changes: 3 additions & 5 deletions scripts/build-all.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ args:
---*/

import usePantry from "hooks/usePantry.ts"
import hydrate from "prefab/hydrate.ts"
import build from "prefab/build.ts"
import doInstall from "prefab/install.ts"
import { lvl1 as link } from "prefab/link.ts"
Expand Down Expand Up @@ -95,16 +94,15 @@ async function buildIfNeeded({ project, install }: BuildOptions) {
console.verbose({ building: project })
}

const deps = await pantry.getDeps({ pkg, wbuild: true })
const graph = await hydrate(deps)
const deps = await pantry.getDeps(pkg)

for (const dep of graph) {
for (const dep of [...deps.build, ...deps.runtime]) {
await buildIfNeeded({ project: dep, install: true })
}

await prepare(pkg)
try {
const path = await build({ pkg, deps: graph })
const path = await build({ pkg, deps })
await link({ path, pkg })
results.built.push(`${pkg.project}-${pkg.version.version}`)
} catch (error) {
Expand Down
3 changes: 1 addition & 2 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ args:
- --import-map={{ srcroot }}/import-map.json
---*/

import hydrate from "prefab/hydrate.ts"
import build from "prefab/build.ts"
import { lvl1 as link } from "prefab/link.ts"
import usePantry from "hooks/usePantry.ts"
Expand All @@ -39,7 +38,7 @@ for (const req of args[0].map(parsePackageRequirement)) {
if (!version) throw "no-version-found"
const pkg = { project: req.project, version }
console.debug(pkg)
const deps = await pantry.getDeps({ pkg, wbuild: true })
const deps = await pantry.getDeps(pkg)

console.debug({ deps })

Expand Down
14 changes: 6 additions & 8 deletions src/hooks/usePantry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@ import useCellar from "hooks/useCellar.ts"
import usePlatform from "hooks/usePlatform.ts"


interface GetDepsOptions {
pkg: Package | PackageRequirement
wbuild?: boolean
}

interface Response {
getDistributable(rq: Package): Promise<{ url: string, stripComponents?: number }>
/// returns sorted versions
getVersions(rq: PackageRequirement | Package): Promise<SemVer[]>
getDeps(opts: GetDepsOptions): Promise<PackageRequirement[]>
getDeps(pkg: Package | PackageRequirement): Promise<{ runtime: PackageRequirement[], build: PackageRequirement[] }>
getBuildScript(pkg: Package): Promise<string>
update(): Promise<void>
getProvides(rq: PackageRequirement | Package): Promise<string[]>
Expand Down Expand Up @@ -74,9 +69,12 @@ export default function usePantry(): Response {
}
}

const getDeps = async ({pkg, wbuild}: GetDepsOptions) => {
const getDeps = async (pkg: Package | PackageRequirement) => {
const yml = await entry(pkg).yml()
return go(yml.dependencies).concat(go(wbuild && yml.build?.dependencies))
return {
runtime: go(yml.dependencies),
build: go(yml.build?.dependencies)
}
// deno-lint-ignore no-explicit-any
function go(node: any) {
if (!node) return []
Expand Down
52 changes: 49 additions & 3 deletions src/prefab/build.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Path, Package, PackageRequirement } from "types"
import { Path, Package, PackageRequirement, semver } from "types"
import usePantry from "hooks/usePantry.ts"
import useCellar from "hooks/useCellar.ts"
import useShellEnv from "hooks/useShellEnv.ts"
Expand All @@ -7,14 +7,17 @@ import usePlatform from "hooks/usePlatform.ts";

interface Options {
pkg: Package
deps: PackageRequirement[]
deps: {
build: PackageRequirement[]
runtime: PackageRequirement[]
}
}

export default async function build({ pkg, deps }: Options): Promise<Path> {
const pantry = usePantry()
const dst = useCellar().mkpath(pkg)
const src = dst.join("src")
const env = await useShellEnv(deps)
const env = await useShellEnv([...deps.build, ...deps.runtime])
const sh = await pantry.getBuildScript(pkg)
const { platform } = usePlatform()

Expand All @@ -40,6 +43,10 @@ export default async function build({ pkg, deps }: Options): Promise<Path> {
}).chmod(0o500)

await run({ cmd })
await fix(dst, [
...deps.runtime,
{project: pkg.project, constraint: new semver.Range(`=${pkg.version}`)}
] )

return dst
}
Expand All @@ -52,3 +59,42 @@ function expand(env: Record<string, string[]>) {
}
return rv
}

async function* exefiles(prefix: Path) {
for (const basename of ["bin", "lib"]) { //TODO the rest
const d = prefix.join(basename).isDirectory()
if (!d) continue
for await (const [exename] of d.ls()) {
if (exename.isExecutableFile()) yield exename
}
}
}

/// fix rpaths or install names for executables and dynamic libraries
async function fix(prefix: Path, pkgs: PackageRequirement[]) {
if (usePlatform().platform != 'linux') return
// ^^ TODO we need to do this on mac too

for await (const exename of exefiles(prefix)) {
await setRpath(exename, pkgs)
}
}

//TODO this is not resilient to upgrades (obv)
async function setRpath(exename: Path, pkgs: PackageRequirement[]) {
const cellar = useCellar()
const rpath = (await Promise.all(pkgs.map(pkg => prefix(pkg)))).join(":")

try {
await run({
cmd: ["patchelf", "--set-rpath", rpath, exename]
})
} catch (e) {
console.warn(e)
//FIXME we skip all errors as we are not checking if files are executables rather than eg. scripts
}

async function prefix(pkg: PackageRequirement) {
return (await cellar.resolve(pkg)).path.join("lib").string
}
}
2 changes: 1 addition & 1 deletion src/prefab/hydrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default async function hydrate(reqs: PackageRequirement[]): Promise<Packa
while (stack.length > 0) {
const curr = stack.shift()!

for (const dep of await pantry.getDeps({ pkg: curr })) {
for (const dep of (await pantry.getDeps(curr)).runtime) {
if (dep.project in set) {
const intersection = semver_intersection(set[dep.project]!, dep.constraint)
// ^^ throws if no intersection possible
Expand Down

0 comments on commit 08c7609

Please sign in to comment.