diff --git a/src/builder/darwin.ts b/src/builder/darwin.ts index cfb44987..af273d23 100644 --- a/src/builder/darwin.ts +++ b/src/builder/darwin.ts @@ -20,6 +20,7 @@ import * as io from '@actions/io'; import * as tc from '@actions/tool-cache'; import {ssl102Url, sslUrl} from '../constants'; import Builder from './builder'; +import fs from 'fs'; import os from 'os'; import path from 'path'; import semver from 'semver'; @@ -28,40 +29,67 @@ export default class MacOSBuilder extends Builder { private sslPath = ''; override async build(): Promise { + process.env['LDFLAGS'] = ''; + process.env['CFLAGS'] = '-Wno-implicit-function-declaration '; + process.env['CPPFLAGS'] = ''; + // Prepare envirnoment + core.debug('Preparing runner environment for build...'); await this.prepareEnvironment(); core.debug('Environment ready.'); // Prepare sources + core.debug('Preparing sources...'); await this.prepareSources(); core.debug('Sources ready'); // Configuring flags - const flags: string[] = ['--enable-shared']; + + const flags: string[] = []; if (semver.lt(this.specificVersion, '3.0.0')) { flags.push('--enable-unicode=ucs4'); } - if (semver.gte(this.specificVersion, '3.6.0')) { + if (semver.gte(this.specificVersion, '3.2.0')) { flags.push('--enable-loadable-sqlite-extensions'); + let sqlite = ''; + await exec.exec('brew --prefix sqlite3', [], { + listeners: { + stdout: (buffer: Buffer) => { + sqlite += buffer.toString(); + } + }, + silent: true + }); + sqlite = sqlite.trim(); + core.info(`sqlite3 module path: ${sqlite}`); + process.env['LDFLAGS'] += ` -L${sqlite}/lib`; + process.env['CFLAGS'] += ` -I${sqlite}/include`; + process.env['CPPFLAGS'] += `-I${sqlite}/include`; } if (semver.gte(this.specificVersion, '3.7.0')) { flags.push('--enable-optimizations'); + flags.push('--with-lto'); + flags.push(`--with-openssl=${this.sslPath}`); } const configCommand = './configure '.concat( - `--prefix=${path.join(this.path, this.buildSuffix())} --with-ssl=${ - this.sslPath - } `, + `--prefix=${path.join(this.path, this.buildSuffix())} `, flags.join(' ') ); // Running ./configure + core.startGroup('Configuring makefile'); + core.info(`Config command: ${configCommand}`); + core.info(`CFLAGS: ${process.env['CFLAGS']}`); + core.info(`LDFLAGS: ${process.env['LDFLAGS']}`); + core.info(`CPPFLAGS: ${process.env['CPPFLAGS']}`); await exec.exec(configCommand, [], {cwd: this.path}); core.endGroup(); // Running make and make install + core.startGroup('Running make'); await exec.exec('make', [], {cwd: this.path}); core.endGroup(); @@ -87,20 +115,31 @@ export default class MacOSBuilder extends Builder { await exec.exec('xcode-select --install', [], {ignoreReturnCode: true}); - // Use older compilers for python versions >3.7 + // Install general dependencies - if (semver.lt(this.specificVersion, '3.5.0')) { - core.info('Detected version <3.5. An older compiler will be used...'); - await exec.exec('brew install gcc@9'); - process.env['CC'] = 'gcc-9'; - } else if (semver.lt(this.specificVersion, '3.7.0')) { - core.info('Detected version <3.7. An older compiler will be used...'); - await exec.exec('brew install gcc@10'); - process.env['CC'] = 'gcc-10'; - } + await this.installGeneralDependencies(); // Install ssl + let zlibPath = ''; + await exec.exec('brew --prefix zlib', [], { + listeners: { + stdout: (buffer: Buffer) => { + zlibPath = zlibPath.concat(buffer.toString()); + } + } + }); + zlibPath = zlibPath.trim(); + let readLinePath = ''; + await exec.exec('brew --prefix readline', [], { + listeners: { + stdout: (buffer: Buffer) => { + readLinePath = readLinePath.concat(buffer.toString()); + } + } + }); + readLinePath = readLinePath.trim(); + if (semver.lt(this.specificVersion, '3.5.0')) { core.info('Detected version <3.5. OpenSSL version 1.0.2 will be used...'); this.sslPath = await this.installOldSsl(ssl102Url); @@ -127,6 +166,15 @@ export default class MacOSBuilder extends Builder { } }); } + this.sslPath = this.sslPath.trim(); + if (semver.lt(this.specificVersion, '3.7.0')) { + process.env[ + 'LDFLAGS' + ] += `-L${this.sslPath}/lib -L${zlibPath}/lib -L${readLinePath}/lib`; + process.env[ + 'CFLAGS' + ] += `-I${this.sslPath}/include -I${zlibPath}/include -I${readLinePath}/lib`; + } core.info(`OpenSSL path: ${this.sslPath}`); // Fix for Python 3.0 SVN version @@ -147,14 +195,16 @@ export default class MacOSBuilder extends Builder { override async postInstall(installedPath: string): Promise { core.startGroup('Performing post-install operations'); - core.info(`InstallDir: ${installedPath}`); + // Install general dependencies + + await this.installGeneralDependencies(); // Handle ssl installations if (semver.lt(this.specificVersion, '3.5.0')) { core.info('Detected version <3.5. OpenSSL version 1.0.2 will be used...'); if (this.sslPath === '') { - this.sslPath = await this.installOldSsl(ssl102Url); + await this.installOldSsl(ssl102Url); } else { core.info('OpenSSL version 1.0.2 is already installed.'); } @@ -162,14 +212,6 @@ export default class MacOSBuilder extends Builder { core.info('Detected version <3.9. OpenSSL version 1.1 will be used...'); if (this.sslPath === '') { await exec.exec('brew install openssl@1.1'); - this.sslPath = ''; - await exec.exec('brew --prefix openssl@1.1', [], { - listeners: { - stdout: (buffer: Buffer) => { - this.sslPath = this.sslPath.concat(buffer.toString()); - } - } - }); } else { core.info('OpenSSL version 1.1 is already installed.'); } @@ -177,19 +219,56 @@ export default class MacOSBuilder extends Builder { core.info('Detected version >=3.9. Default OpenSSL will be used...'); if (this.sslPath === '') { await exec.exec('brew install openssl'); - this.sslPath = ''; - await exec.exec('brew --prefix openssl', [], { - listeners: { - stdout: (buffer: Buffer) => { - this.sslPath = this.sslPath.concat(buffer.toString()); - } - } - }); } else { core.info('OpenSSL is already installed.'); } } + // Create symlinks + + const splitVersion = this.specificVersion.split('.'); + const majorDotMinorString = `${splitVersion[0]}.${splitVersion[1]}`; + const majorMinorString = `${splitVersion[0]}${splitVersion[1]}`; + const pythonExecutable = path.join( + installedPath, + 'bin', + `python${majorDotMinorString}` + ); + core.info('Creating python symlinks...'); + const mainExecutable = path.join(installedPath, 'python'); + core.info(`Creating symlink from ${pythonExecutable} to ${mainExecutable}`); + fs.symlinkSync(pythonExecutable, mainExecutable); + const binExecutable = path.join( + installedPath, + 'bin', + `python${majorMinorString}` + ); + core.info(`Creating symlink from ${pythonExecutable} to ${binExecutable}`); + fs.symlinkSync(pythonExecutable, binExecutable); + if ( + semver.gte(this.specificVersion, '3.0.0') && + semver.lt(this.specificVersion, '3.1.0') + ) { + const python3Executable = path.join(installedPath, 'bin', 'python3'); + core.info( + `Creating symlink from ${pythonExecutable} to ${python3Executable}` + ); + fs.symlinkSync(pythonExecutable, python3Executable); + } + + // Add executable bits + + const executables = [ + pythonExecutable, + mainExecutable, + binExecutable, + path.join(installedPath, 'bin', 'python3') + ]; + for (const executable of executables) { + core.info(`Adding executable bit to ${executable}`); + await exec.exec(`chmod +x ${executable}`); + } + core.endGroup(); } @@ -212,4 +291,10 @@ export default class MacOSBuilder extends Builder { await io.rmRF(ssl); return installPath; } + + private async installGeneralDependencies(): Promise { + await exec.exec('brew install zlib', [], {ignoreReturnCode: true}); + await exec.exec('brew install sqlite3', [], {ignoreReturnCode: true}); + await exec.exec('brew install readline', [], {ignoreReturnCode: true}); + } } diff --git a/src/builder/linux.ts b/src/builder/linux.ts index e4c99d5e..6d4abbaa 100644 --- a/src/builder/linux.ts +++ b/src/builder/linux.ts @@ -29,16 +29,19 @@ export default class LinuxBuilder extends Builder { override async build(): Promise { // Prepare envirnoment + core.debug('Preparing runner environment for build...'); await this.prepareEnvironment(); core.debug('Environment ready.'); // Prepare sources + core.debug('Preparing sources...'); await this.prepareSources(); core.debug('Sources ready'); // Configuring flags + const flags: string[] = ['--enable-shared']; if (semver.lt(this.specificVersion, '3.0.0')) { flags.push('--enable-unicode=ucs4'); @@ -54,12 +57,14 @@ export default class LinuxBuilder extends Builder { flags.join(' ') ); - // Running ./configure + // Run ./configure + core.startGroup('Configuring makefile'); await exec.exec(configCommand, [], {cwd: this.path}); core.endGroup(); - // Running make and make install + // Run make and make install + core.startGroup('Running make'); await exec.exec('make', [], {cwd: this.path}); core.endGroup(); @@ -123,11 +128,13 @@ export default class LinuxBuilder extends Builder { core.startGroup('Performing post-install operations'); // Install old ssl + if (semver.lt(this.specificVersion, '3.5.0')) { await this.installOldSsl(); } // Create symlinks + const splitVersion = this.specificVersion.split('.'); const majorDotMinorString = `${splitVersion[0]}.${splitVersion[1]}`; const majorMinorString = `${splitVersion[0]}${splitVersion[1]}`; @@ -158,7 +165,8 @@ export default class LinuxBuilder extends Builder { fs.symlinkSync(pythonExecutable, python3Executable); } - // Adding executable bits + // Add executable bits + const executables = [ pythonExecutable, mainExecutable, diff --git a/src/builder/windows.ts b/src/builder/windows.ts index bdeef1da..1b961927 100644 --- a/src/builder/windows.ts +++ b/src/builder/windows.ts @@ -31,11 +31,13 @@ export default class WindowsBuilder extends Builder { override async build(): Promise { // Prepare envirnoment + core.debug('Preparing runner environment for build...'); await this.prepareEnvironment(); core.debug('Environment ready.'); // Prepare sources + core.debug('Preparing sources...'); await this.prepareSources(); core.debug('Sources ready'); @@ -44,9 +46,11 @@ export default class WindowsBuilder extends Builder { let returnPath: string; // Build python + const buildFile = path.join(this.path, 'Tools', 'msi', 'build.bat'); if (fs.existsSync(buildFile)) { // Can build with msi tool + const externalsMsi = path.join( this.path, 'Tools', @@ -79,6 +83,7 @@ export default class WindowsBuilder extends Builder { core.startGroup('Installing Python to temp folder'); // Detecting installer full path + let buildPath = path.join(this.path, 'PCbuild'); switch (this.arch) { case 'x64': @@ -103,6 +108,7 @@ export default class WindowsBuilder extends Builder { core.info(`Installer: ${installer}`); // Generating exec arguments + const execArguments: string[] = [ `TargetDir=${path.join(this.path, this.buildSuffix())}`, 'Include_pip=0', @@ -129,6 +135,7 @@ export default class WindowsBuilder extends Builder { } // Cleaning environment + core.debug('Cleaning environment...'); await this.cleanEnvironment(); core.debug('Environment cleaned'); @@ -146,6 +153,7 @@ export default class WindowsBuilder extends Builder { private async prepareEnvironment(): Promise { // Detect MSBUILD + core.startGroup('Searching for msbuild.exe'); try { await exec.exec('vswhere', [], {silent: true}); @@ -171,6 +179,7 @@ export default class WindowsBuilder extends Builder { core.endGroup(); // Detect Visual Studio + core.startGroup('Searching for Visual Studio'); let vsPath = ''; await exec.exec('vswhere -property installationPath', [], { @@ -185,6 +194,7 @@ export default class WindowsBuilder extends Builder { core.endGroup(); // Installing dependencies + core.startGroup('Installing dependencies'); const installer = await tc.downloadTool( vsInstallerUrl, @@ -223,6 +233,7 @@ export default class WindowsBuilder extends Builder { core.startGroup('Performing post-install operations'); // Create python3 symlink + if (semver.gte(this.specificVersion, '3.0.0')) { const currentExecutable = path.join(installedPath, 'python.exe'); if (!fs.existsSync(currentExecutable)) {