Skip to content

Commit 8b3f5fa

Browse files
committed
chore: wip
1 parent dfd2058 commit 8b3f5fa

File tree

4 files changed

+317
-3
lines changed

4 files changed

+317
-3
lines changed

.github/workflows/build-binaries.yml

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,10 @@ jobs:
254254
INSTALL_PREFIX="${{ env.OUTPUT_DIR }}/${{ env.BINARY_NAME }}"
255255
mkdir -p "$INSTALL_PREFIX"
256256
257+
# Set up launchpad build environment
258+
echo "Setting up launchpad build environment..."
259+
source "$HOME/.local/share/launchpad/global/build-env.sh"
260+
257261
# Configure with platform-specific options
258262
if [[ "${{ matrix.platform }}" == "darwin" ]]; then
259263
# On macOS, point to Homebrew iconv installation
@@ -267,19 +271,52 @@ jobs:
267271
echo " Extensions: ${{ env.CONFIGURE_EXTENSIONS }}"
268272
echo " Prefix: $INSTALL_PREFIX"
269273
echo " Extra config: $EXTRA_CONFIG"
274+
echo " PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
275+
echo " LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
276+
277+
# Debug: Show available pkg-config files
278+
echo "Available pkg-config files:"
279+
pkg-config --list-all | grep -i curl || echo "No curl pkg-config found"
280+
echo "libcurl pkg-config info:"
281+
pkg-config --exists libcurl && pkg-config --modversion libcurl || echo "libcurl not found via pkg-config"
282+
283+
# Show all available pkg-config files for debugging
284+
echo "All available pkg-config files:"
285+
pkg-config --list-all | head -20
286+
echo "... (showing first 20)"
287+
288+
# Check if libcurl is found via pkg-config
289+
if pkg-config --exists libcurl; then
290+
echo "libcurl found via pkg-config"
291+
CURL_CONFIG=""
292+
else
293+
echo "libcurl not found via pkg-config, using manual configuration"
294+
CURL_CONFIG="--with-curl=$HOME/.local/share/launchpad/global/curl.se/v8.15.0"
295+
fi
296+
297+
# Check for other common libraries
298+
echo "Checking for other required libraries:"
299+
pkg-config --exists openssl && echo "✓ openssl found" || echo "✗ openssl not found"
300+
pkg-config --exists zlib && echo "✓ zlib found" || echo "✗ zlib not found"
301+
pkg-config --exists libxml-2.0 && echo "✓ libxml-2.0 found" || echo "✗ libxml-2.0 not found"
302+
pkg-config --exists sqlite3 && echo "✓ sqlite3 found" || echo "✗ sqlite3 not found"
270303
271304
./configure \
272305
--prefix="$INSTALL_PREFIX" \
273306
--disable-debug \
274307
--enable-shared \
275308
--with-pic \
276309
${{ env.CONFIGURE_EXTENSIONS }} \
277-
$EXTRA_CONFIG
310+
$EXTRA_CONFIG \
311+
$CURL_CONFIG
278312
279313
- name: Build PHP
280314
run: |
281315
cd ${{ env.PHP_SOURCE_DIR }}
282316
317+
# Set up launchpad build environment for compilation
318+
source "$HOME/.local/share/launchpad/global/build-env.sh"
319+
283320
# Use all available CPU cores for faster builds
284321
if [[ "${{ matrix.platform }}" == "darwin" ]]; then
285322
JOBS=$(sysctl -n hw.ncpu)

packages/launchpad/bin/cli.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3348,6 +3348,43 @@ cli
33483348
}
33493349
})
33503350

3351+
// Build environment command
3352+
cli
3353+
.command('build-env', 'Set up build environment for launchpad-installed packages')
3354+
.alias('env')
3355+
.option('--path <path>', 'Custom installation path')
3356+
.option('--shell', 'Output shell code for evaluation (use with eval)')
3357+
.example('launchpad build-env')
3358+
.example('launchpad build-env --path ~/.local/share/launchpad/global')
3359+
.example('launchpad build-env --shell | source /dev/stdin')
3360+
.action(async (options?: { path?: string, shell?: boolean }) => {
3361+
try {
3362+
const defaultInstallPath = path.join(homedir(), '.local', 'share', 'launchpad', 'global')
3363+
const installPath = options?.path || defaultInstallPath
3364+
const buildEnvScript = path.join(installPath, 'build-env.sh')
3365+
3366+
if (!fs.existsSync(buildEnvScript)) {
3367+
console.error('❌ Build environment script not found. Please install some packages first.')
3368+
console.error(` Expected location: ${buildEnvScript}`)
3369+
process.exit(1)
3370+
}
3371+
3372+
if (options?.shell) {
3373+
// Output the script content for shell evaluation
3374+
const scriptContent = fs.readFileSync(buildEnvScript, 'utf-8')
3375+
console.log(scriptContent)
3376+
} else {
3377+
// Execute the script directly
3378+
const { execSync } = await import('node:child_process')
3379+
execSync(`source "${buildEnvScript}"`, { stdio: 'inherit', shell: '/bin/sh' })
3380+
}
3381+
}
3382+
catch (error) {
3383+
console.error('Failed to set up build environment:', error instanceof Error ? error.message : String(error))
3384+
process.exit(1)
3385+
}
3386+
})
3387+
33513388
// Parse CLI arguments
33523389
try {
33533390
cli.version(version)

packages/launchpad/src/install-core.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import process from 'node:process'
77
import { install_bun } from './bun'
88
import { getCachedPackagePath, savePackageToCache } from './cache'
99
import { config } from './config'
10-
import { createShims, createVersionCompatibilitySymlinks, createVersionSymlinks, validatePackageInstallation } from './install-helpers'
10+
import { createShims, createVersionCompatibilitySymlinks, createVersionSymlinks, validatePackageInstallation, createBuildEnvironmentScript } from './install-helpers'
1111
import { cleanupSpinner, logUniqueMessage } from './logging'
1212
import { getLatestVersion, parsePackageSpec, resolvePackageName, resolveVersion } from './package-resolution'
1313
import { installMeilisearch } from './special-installers'
@@ -888,6 +888,9 @@ export async function downloadPackage(
888888
// Find binaries and create shims
889889
const installedBinaries = await createShims(packageDir, installPath, domain, version)
890890

891+
// Create comprehensive build environment script
892+
await createBuildEnvironmentScript(installPath)
893+
891894
// Create package metadata for tracking
892895
const metadata = {
893896
domain,

packages/launchpad/src/install-helpers.ts

Lines changed: 238 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,80 @@ export async function createShims(packageDir: string, installPath: string, domai
118118
return libraryPaths
119119
}
120120

121+
// Helper function to build pkg-config paths for all installed packages
122+
function buildPkgConfigPaths(installPath: string): string[] {
123+
const pkgConfigPaths: string[] = []
124+
125+
try {
126+
const domains = fs.readdirSync(installPath, { withFileTypes: true })
127+
.filter(dirent => dirent.isDirectory()
128+
&& !['bin', 'sbin', 'lib', 'lib64', 'share', 'include', 'etc', 'pkgs', '.tmp', '.cache'].includes(dirent.name))
129+
130+
for (const domainEntry of domains) {
131+
const domainPath = path.join(installPath, domainEntry.name)
132+
if (fs.existsSync(domainPath)) {
133+
const versions = fs.readdirSync(domainPath, { withFileTypes: true })
134+
.filter(dirent => dirent.isDirectory() && dirent.name.startsWith('v'))
135+
136+
for (const versionEntry of versions) {
137+
const versionPath = path.join(domainPath, versionEntry.name)
138+
const pkgConfigDirs = [
139+
path.join(versionPath, 'lib', 'pkgconfig'),
140+
path.join(versionPath, 'lib64', 'pkgconfig'),
141+
]
142+
143+
for (const pkgConfigDir of pkgConfigDirs) {
144+
if (fs.existsSync(pkgConfigDir) && !pkgConfigPaths.includes(pkgConfigDir)) {
145+
pkgConfigPaths.push(pkgConfigDir)
146+
}
147+
}
148+
}
149+
}
150+
}
151+
}
152+
catch {
153+
// Ignore errors reading directories
154+
}
155+
156+
return pkgConfigPaths
157+
}
158+
159+
// Helper function to build include paths for all installed packages
160+
function buildIncludePaths(installPath: string): string[] {
161+
const includePaths: string[] = []
162+
163+
try {
164+
const domains = fs.readdirSync(installPath, { withFileTypes: true })
165+
.filter(dirent => dirent.isDirectory()
166+
&& !['bin', 'sbin', 'lib', 'lib64', 'share', 'include', 'etc', 'pkgs', '.tmp', '.cache'].includes(dirent.name))
167+
168+
for (const domainEntry of domains) {
169+
const domainPath = path.join(installPath, domainEntry.name)
170+
if (fs.existsSync(domainPath)) {
171+
const versions = fs.readdirSync(domainPath, { withFileTypes: true })
172+
.filter(dirent => dirent.isDirectory() && dirent.name.startsWith('v'))
173+
174+
for (const versionEntry of versions) {
175+
const versionPath = path.join(domainPath, versionEntry.name)
176+
const includeDir = path.join(versionPath, 'include')
177+
178+
if (fs.existsSync(includeDir) && !includePaths.includes(includeDir)) {
179+
includePaths.push(includeDir)
180+
}
181+
}
182+
}
183+
}
184+
}
185+
catch {
186+
// Ignore errors reading directories
187+
}
188+
189+
return includePaths
190+
}
191+
121192
const libraryPaths = buildLibraryPaths(packageDir, installPath)
193+
const pkgConfigPaths = buildPkgConfigPaths(installPath)
194+
const includePaths = buildIncludePaths(installPath)
122195

123196
for (const { sourceDir, shimDir: targetShimDir } of binaryDirs) {
124197
if (!fs.existsSync(sourceDir)) {
@@ -139,9 +212,10 @@ export async function createShims(packageDir: string, installPath: string, domai
139212
let shimContent = `#!/bin/sh
140213
# Launchpad shim for ${binary} (${domain} v${version})
141214
142-
# Set up library paths for dynamic linking
215+
# Set up comprehensive build environment for launchpad-installed packages
143216
`
144217

218+
// Set up library paths for dynamic linking
145219
if (libraryPaths.length > 0) {
146220
const libraryPathString = libraryPaths.join(':')
147221
shimContent += `# macOS dynamic library paths
@@ -164,6 +238,39 @@ else
164238
export LD_LIBRARY_PATH="${libraryPathString}"
165239
fi
166240
241+
`
242+
}
243+
244+
// Set up pkg-config paths for build tools
245+
if (pkgConfigPaths.length > 0) {
246+
const pkgConfigPathString = pkgConfigPaths.join(':')
247+
shimContent += `# Set up pkg-config to find launchpad-installed libraries
248+
if [ -n "$PKG_CONFIG_PATH" ]; then
249+
export PKG_CONFIG_PATH="${pkgConfigPathString}:$PKG_CONFIG_PATH"
250+
else
251+
export PKG_CONFIG_PATH="${pkgConfigPathString}"
252+
fi
253+
254+
`
255+
}
256+
257+
// Set up include paths for compilation
258+
if (includePaths.length > 0) {
259+
const includePathString = includePaths.join(' ')
260+
shimContent += `# Set up include paths for compilation
261+
if [ -n "$CPPFLAGS" ]; then
262+
export CPPFLAGS="-I${includePathString} $CPPFLAGS"
263+
else
264+
export CPPFLAGS="-I${includePathString}"
265+
fi
266+
267+
# Set up library paths for linking
268+
if [ -n "$LDFLAGS" ]; then
269+
export LDFLAGS="-L${libraryPaths.join(' -L')} $LDFLAGS"
270+
else
271+
export LDFLAGS="-L${libraryPaths.join(' -L')}"
272+
fi
273+
167274
`
168275
}
169276

@@ -444,3 +551,133 @@ export async function validatePackageInstallation(packageDir: string, domain: st
444551
return true // Assume valid if we can't check
445552
}
446553
}
554+
555+
/**
556+
* Create a comprehensive environment setup script for build tools
557+
* This script can be sourced to set up all launchpad-installed packages for building
558+
*/
559+
export async function createBuildEnvironmentScript(installPath: string): Promise<void> {
560+
const scriptPath = path.join(installPath, 'build-env.sh')
561+
562+
// Build all the paths
563+
const libraryPaths: string[] = []
564+
const pkgConfigPaths: string[] = []
565+
const includePaths: string[] = []
566+
const binPaths: string[] = []
567+
568+
try {
569+
const domains = fs.readdirSync(installPath, { withFileTypes: true })
570+
.filter(dirent => dirent.isDirectory()
571+
&& !['bin', 'sbin', 'lib', 'lib64', 'share', 'include', 'etc', 'pkgs', '.tmp', '.cache'].includes(dirent.name))
572+
573+
for (const domainEntry of domains) {
574+
const domainPath = path.join(installPath, domainEntry.name)
575+
if (fs.existsSync(domainPath)) {
576+
const versions = fs.readdirSync(domainPath, { withFileTypes: true })
577+
.filter(dirent => dirent.isDirectory() && dirent.name.startsWith('v'))
578+
579+
for (const versionEntry of versions) {
580+
const versionPath = path.join(domainPath, versionEntry.name)
581+
582+
// Add library paths
583+
const libDirs = [
584+
path.join(versionPath, 'lib'),
585+
path.join(versionPath, 'lib64'),
586+
]
587+
for (const libDir of libDirs) {
588+
if (fs.existsSync(libDir) && !libraryPaths.includes(libDir)) {
589+
libraryPaths.push(libDir)
590+
}
591+
}
592+
593+
// Add pkg-config paths
594+
const pkgConfigDirs = [
595+
path.join(versionPath, 'lib', 'pkgconfig'),
596+
path.join(versionPath, 'lib64', 'pkgconfig'),
597+
]
598+
for (const pkgConfigDir of pkgConfigDirs) {
599+
if (fs.existsSync(pkgConfigDir) && !pkgConfigPaths.includes(pkgConfigDir)) {
600+
pkgConfigPaths.push(pkgConfigDir)
601+
}
602+
}
603+
604+
// Add include paths
605+
const includeDir = path.join(versionPath, 'include')
606+
if (fs.existsSync(includeDir) && !includePaths.includes(includeDir)) {
607+
includePaths.push(includeDir)
608+
}
609+
610+
// Add bin paths
611+
const binDir = path.join(versionPath, 'bin')
612+
if (fs.existsSync(binDir) && !binPaths.includes(binDir)) {
613+
binPaths.push(binDir)
614+
}
615+
}
616+
}
617+
}
618+
}
619+
catch {
620+
// Ignore errors reading directories
621+
}
622+
623+
// Create the environment setup script
624+
let scriptContent = `#!/bin/sh
625+
# Launchpad Build Environment Setup Script
626+
# Source this script to set up environment for building with launchpad-installed packages
627+
628+
# Set up PATH to include launchpad binaries
629+
if [ -n "$PATH" ]; then
630+
export PATH="${binPaths.join(':')}:$PATH"
631+
else
632+
export PATH="${binPaths.join(':')}"
633+
fi
634+
635+
`
636+
637+
// Set up library paths
638+
if (libraryPaths.length > 0) {
639+
const libraryPathString = libraryPaths.join(':')
640+
scriptContent += `# Set up library paths for dynamic linking
641+
export LD_LIBRARY_PATH="${libraryPathString}${process.platform === 'darwin' ? ':$LD_LIBRARY_PATH' : ''}"
642+
export DYLD_LIBRARY_PATH="${libraryPathString}${process.platform === 'darwin' ? ':$DYLD_LIBRARY_PATH' : ''}"
643+
export DYLD_FALLBACK_LIBRARY_PATH="${libraryPathString}:/usr/local/lib:/lib:/usr/lib"
644+
645+
`
646+
}
647+
648+
// Set up pkg-config paths
649+
if (pkgConfigPaths.length > 0) {
650+
const pkgConfigPathString = pkgConfigPaths.join(':')
651+
scriptContent += `# Set up pkg-config to find launchpad-installed libraries
652+
export PKG_CONFIG_PATH="${pkgConfigPathString}${process.env.PKG_CONFIG_PATH ? ':' + process.env.PKG_CONFIG_PATH : ''}"
653+
654+
`
655+
}
656+
657+
// Set up include and library paths for compilation
658+
if (includePaths.length > 0 || libraryPaths.length > 0) {
659+
scriptContent += `# Set up include paths for compilation
660+
export CPPFLAGS="-I${includePaths.join(' -I')}${process.env.CPPFLAGS ? ' ' + process.env.CPPFLAGS : ''}"
661+
662+
# Set up library paths for linking
663+
export LDFLAGS="-L${libraryPaths.join(' -L')}${process.env.LDFLAGS ? ' ' + process.env.LDFLAGS : ''}"
664+
665+
`
666+
}
667+
668+
scriptContent += `# Print environment info
669+
echo "Launchpad build environment activated:"
670+
echo " PATH: $PATH"
671+
echo " LD_LIBRARY_PATH: $LD_LIBRARY_PATH"
672+
echo " PKG_CONFIG_PATH: $PKG_CONFIG_PATH"
673+
echo " CPPFLAGS: $CPPFLAGS"
674+
echo " LDFLAGS: $LDFLAGS"
675+
`
676+
677+
await fs.promises.writeFile(scriptPath, scriptContent)
678+
await fs.promises.chmod(scriptPath, 0o755)
679+
680+
if (config.verbose) {
681+
console.warn(`Created build environment script: ${scriptPath}`)
682+
}
683+
}

0 commit comments

Comments
 (0)