#!/usr/bin/hphpi -f
<?php
-require( dirname( __FILE__ ) . '/../Maintenance.php' );
+define( 'MW_CONFIG_CALLBACK', 'MakeHipHop::noConfigNeeded' );
+require( __DIR__ . '/../Maintenance.php' );
class MakeHipHop extends Maintenance {
+ function noConfigNeeded() {}
function execute() {
+ global $wgHipHopBuildDirectory;
+
$startTime = time();
- $sourceDir = realpath( dirname( __FILE__ ) );
- $IP = realpath( "$sourceDir/../.." );
- $buildDir = "$sourceDir/build";
+ $thisDir = realpath( __DIR__ );
+ $IP = realpath( "$thisDir/../.." );
+ if ( strval( $wgHipHopBuildDirectory ) !== '' ) {
+ $buildDir = $wgHipHopBuildDirectory;
+ } else {
+ $buildDir = "$thisDir/build";
+ }
+ $extensionsDir = realpath( MWInit::getExtensionsDirectory() );
$outDir = "$buildDir/hiphop-output";
- $persistentDir = "$buildDir/persistent" ;
+ $persistentDir = "$buildDir/persistent";
if ( !is_dir( $buildDir ) ) {
mkdir( $buildDir, 0777, true );
mkdir( $persistentDir, 0777, true );
}
+ if ( realpath( "$IP/../phase3" ) !== $IP
+ || realpath( "$IP/../extensions" ) !== $extensionsDir )
+ {
+ # Set up a fake source directory with the correct layout
+ $sourceBase = "$buildDir/source";
+ $this->setupFakeSourceBase( $IP, $extensionsDir, $sourceBase );
+ } else {
+ $sourceBase = realpath( "$IP/.." );
+ unlink( "$buildDir/source" );
+ }
+
# With the CentOS RPMs, you just get g++44, no g++, so we have to
# use the environment
if ( isset( $_ENV['CXX'] ) ) {
"}\n"
);
+ # Generate the file list
+ $files = $this->getFileList();
+ file_put_contents(
+ "$buildDir/file-list",
+ implode( "\n", $files ) . "\n" );
+
# Generate the C++
passthru(
'hphp' .
' --target=cpp' .
' --format=file' .
- ' --input-dir=' . wfEscapeShellArg( $IP ) .
- ' --input-list=' . wfEscapeShellArg( "$sourceDir/file-list.small" ) .
+ ' --input-dir=' . wfEscapeShellArg( $sourceBase ) .
+ ' --input-list=' . wfEscapeShellArg( "$buildDir/file-list" ) .
' --inputs=' . wfEscapeShellArg( "$buildDir/HipHopCompilerVersion.php" ) .
- ' -c ' . wfEscapeShellArg( "$sourceDir/compiler.conf" ) .
+ ' -c ' . wfEscapeShellArg( "$thisDir/compiler.conf" ) .
' --parse-on-demand=false' .
' --program=mediawiki-hphp' .
' --output-dir=' . wfEscapeShellArg( $outDir ) .
- ' --log=3' );
+ ' --log=3', $ret );
+
+ if ( $ret ) {
+ $this->error( "hphp hit an error. Stopping build.\n" );
+ exit( 1 );
+ }
+
+ # Sanity check, quickly make sure we've got an output directory
+ if( !is_dir( $outDir ) ) {
+ $this->error( "No output directory", true );
+ }
+
+ # Warn about volatile classes
+ $this->checkVolatileClasses( $outDir );
# Copy the generated C++ files into the source directory for cmake
$iter = new RecursiveIteratorIterator(
}
$cmd = 'cmake' .
- ' -D CMAKE_BUILD_TYPE:string=Debug' .
+ " -D CMAKE_BUILD_TYPE:string=" . wfEscapeShellArg( $GLOBALS['wgHipHopBuildType'] ) .
' -D PROGRAM_NAME:string=mediawiki-hphp';
if ( file_exists( '/usr/bin/ccache' ) ) {
# Determine appropriate make concurrency
# Compilation can take a lot of memory, let's assume that that is limiting.
- $mem = false;
- foreach ( file( '/proc/meminfo' ) as $line ) {
- if ( preg_match( '/^MemTotal:\s+(\d+)\s+kB/', $line, $m ) ) {
- $mem = intval( $m[1] );
- break;
- }
- }
- if ( $mem ) {
- $procs = floor( $mem / 1000000 );
- } else {
- $procs = 1;
- }
+ $procs = $this->getNumProcs();
# Run make. This is the slow step.
passthru( 'make -j' . wfEscapeShellArg( $procs ) );
$elapsed -= $minutes * 60;
}
echo $elapsed . "s\n";
- echo "The MediaWiki executable is at build/persistent/mediawiki-hphp\n";
+ echo "The MediaWiki executable is at $buildDir/persistent/mediawiki-hphp\n";
+ }
+
+ function checkVolatileClasses( $dir ) {
+ $lines = file( "$dir/sys/dynamic_table_class.cpp" );
+ $classes = array();
+ foreach ( $lines as $line ) {
+ if ( preg_match( '/^\s+\(const char \*\)"([^"]*)", \(const char \*\)-1/', $line, $m ) ) {
+ $classes[] = $m[1];
+ }
+ }
+ if ( !count( $classes ) ) {
+ print "No volatile classes found\n";
+ return;
+ }
+ sort( $classes );
+ $classes = array_unique( $classes );
+ print "WARNING: The following classes are volatile: " . implode( ', ', $classes ) . "\n";
+ }
+
+ function getNumProcs() {
+ global $wgHipHopCompilerProcs;
+ if ( $wgHipHopCompilerProcs !== 'detect' ) {
+ return intval( $wgHipHopCompilerProcs );
+ }
+
+ if ( !file_exists( '/proc/meminfo' ) ) {
+ return 1;
+ }
+ $mem = false;
+ foreach ( file( '/proc/meminfo' ) as $line ) {
+ if ( preg_match( '/^MemTotal:\s+(\d+)\s+kB/', $line, $m ) ) {
+ $mem = intval( $m[1] );
+ break;
+ }
+ }
+ if ( $mem ) {
+ // At least one process
+ return max( 1, floor( $mem / 1000000 ) );
+ } else {
+ return 1;
+ }
+ }
+
+ function setupFakeSourceBase( $phase3, $extensions, $dest ) {
+ if ( !file_exists( $dest ) ) {
+ mkdir( $dest, 0777, true );
+ }
+
+ $this->forceCreateLink( "$dest/phase3", $phase3 );
+ $this->forceCreateLink( "$dest/extensions", $extensions );
+ }
+
+ function forceCreateLink( $target, $link ) {
+ if ( file_exists( $target ) ) {
+ if ( readlink( $target ) === $link ) {
+ return;
+ }
+ unlink( $target );
+ }
+ symlink( $target, $link );
+ }
+
+ function getFileList() {
+ global $wgAutoloadClasses, $wgAutoloadLocalClasses, $wgCompiledFiles;
+ $inputFiles = array_merge(
+ array_values( $wgAutoloadClasses ),
+ array_values( $wgAutoloadLocalClasses ),
+ $wgCompiledFiles
+ );
+ $processedFiles = array();
+ foreach ( $inputFiles as $file ) {
+ if ( substr( $file, 0, 1 ) === '/' ) {
+ $processedFiles[] = $this->absoluteToRelative( $file );
+ } elseif ( preg_match( '/^extensions/', $file ) ) {
+ $processedFiles[] = $file;
+ } else {
+ $processedFiles[] = "phase3/$file";
+ }
+ }
+
+ $extraCoreFiles = array_map( 'trim', file( __DIR__ . '/extra-files' ) );
+ foreach ( $extraCoreFiles as $file ) {
+ if ( $file === '' ) {
+ continue;
+ }
+ $processedFiles[] = "phase3/$file";
+ }
+ return array_unique( $processedFiles );
+ }
+
+ function absoluteToRelative( $file ) {
+ global $IP;
+
+ $coreBase = realpath( $IP ) . '/';
+ $extBase = realpath( MWInit::getExtensionsDirectory() ) . '/';
+ $file = realpath( $file );
+
+ if ( substr( $file, 0, strlen( $extBase ) ) === $extBase ) {
+ return 'extensions/' . substr( $file, strlen( $extBase ) );
+ } elseif ( substr( $file, 0, strlen( $coreBase ) ) === $coreBase ) {
+ return 'phase3/' . substr( $file, strlen( $coreBase ) );
+ } else {
+ $this->error( "The following file is registered for compilation but is not in \$IP or " .
+ "\$wgExtensionsDirectory: $file \n" );
+ exit( 1 );
+ }
}
}