Prerequisites
1. OS: Windows 8.1, Windows 10 or Windows 2012 R2 x64 and a user with administrative privileges.
2. Windows SDK is installed buy Visual Studio. Apparently the OS-SDK-VS combination is important, as building on Windows 10 with SDK 8.1 does not work.
In case you need to repair/reinstall SDK:
- If building on Windows 8.1 or Windows Server 2012 R2, download Windows SDK 8.1 from https://dev.windows.com/en-us/downloads/windows-8-1-sdk
- If building on Windows 10 or Windows Server 2016, download Windows SDK 10 from https://dev.windows.com/en-us/downloads/windows-10-sdk
3. Build environment:
- Microsoft Visual Studio 2013 Professional or 2015 (Community or Professional)
- Perl 5.22.x binaries from http://www.activestate.com/activeperl/downloads (do not use cygwin or Strawberry perl!)
- CMake 3.5.0 binaries from https://cmake.org/download/
- Gawk binaries for Windows from http://gnuwin32.sourceforge.net/packages/gawk.htm
4. 7Zip for extracting the archives from http://7-zip.org/download.html
5. Apache httpd source code from https://www.apache.org/dist/httpd/
- httpd-2.4.18.tar.gz
- httpd-2.4.18-deps.tar.gz
6. Apache APR iconv sources from https://www.apache.org/dist/apr/
- apr-iconv-1.2.1-win32-src-r2.zip
7. OpenSSL 1.0.x sources from http://openssl.org/source/
- openssl-1.0.2g.tar.gz
8. zLib 1.2.8 sources from http://zlib.net/
- zlib128.zip
9. PCRE 8.xx sources from ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/
- pcre-8.38.zip
- libxml2-2.9.3-win32-x86_64.7z
Note on Windows SDK
Sometimes the installation of Windows SDK will not put all the files and folders in place.
After install, if the folders include and lib are not present in C:\Program Files (x86)\Windows Kits\8.1, run:
"C:\ProgramData\Package Cache\{ed3a6e6d-9661-4357-abe4-fcc03dc57a07}\sdksetup.exe" /repair
Similar for Windows 10 SDK:
"C:\ProgramData\Package Cache\{28a123e5-1799-4f20-9bd8-7c46f30eb7bf}\sdksetup.exe" /repair
Build
The command line building must be run within the VC environment, from a command prompt ran as Administrator.
set PATH=C:\perl64\bin;%PATH%
In order to correctly build Apache httpd server, you need to extract awk.exe from gawk-3.1.6-1-bin.zip, and place it in the %BUILDDIR%.
Build zLib
Zlib archive must be extracted into %BUILDDIR%\srclib subdirectory named zlib.
cd /d %BUILDDIR%\srclib\zlib
nmake -f win32/Makefile.msc AS=ml64 LOC="-DASMV -DASMINF -I." OBJA="inffasx64.obj gvmat64.obj inffas8664.obj"
copy zlib.lib zlib1.lib
Build OpenSSL
OpenSSL archive must be extracted into %BUILDDIR%\srclib subdirectory named openssl.
cd /d %BUILDDIR%\srclib\openssl
perl Configure VC-WIN64A --prefix=/Apache24 --openssldir=/Apache24/conf enable-camellia disable-idea enable-zlib enable-ssl-trace
-I
../zlib -L
../zlib
ms\do_win64a.bat
nmake /f ms\ntdll.mak
Optional, to test OpenSSL:
nmake /f ms\ntdll.mak install
\Apache24\bin\openssl version
Note that OpenSSL binaries will be copied by the Apache installation script anyway.
Build PCRE
Extract PCRE to %BUILDDIR%\srclib and the directory should be named pcre.
PCRE is the only project requiring CMAKE. It will be used to generate the Visual Studio project files. Extract CMAKE binaries in %BUILDDIR%\..\. Shared libraries must be enabled to build mod_proxy_html.
set PATH=%PATH%;%CMAKE_ROOT%\bin
cd /d %BUILDDIR%\srclib\pcre
mkdir build
cd build
cmake -G"Visual Studio 14 2015 Win64" -DBUILD_SHARED_LIBS:BOOL="1" -DPCRE_SUPPORT_UNICODE_PROPERTIES:BOOL="1" -DPCRE_BUILD_PCRE32:BOOL="0" -DPCRE_BUILD_PCRE8:BOOL="1" -DINSTALL_MSVC_PDB:BOOL="1" -DPCRE_SUPPORT_UTF:BOOL="1" -D ZLIB_LIBRARY=%BUILDDIR%\srclib\zlib\zlib.lib -D ZLIB_INCLUDE_DIR=%BUILDDIR%\srclib\zlib ..\
devenv PCRE.sln /useenv /nologo /build "RelWithDebInfo|x64"
copy /Y RelWithDebInfo\pcre.* ..\
Configure the Apache project
Extract:
- Apache httpd source to %BUILDDIR%\..\
- Apache httpd deps to %BUILDDIR%\..\
- Apache APR iconv sources to %BUILDDIR%\srclib in a directory named apr-iconv
- LibXML2 source to %BUILDDIR%\srclib\libxml2
perl srclib\apr\build\lineends.pl
perl srclib\apr\build\cvtdsp.pl -2005
Convert Apache.dsw to the latest Visual Studio solution:
Patch the project files
Because the resulting VS project files are incomplete (most of them are missing the x64 configuration), a custom Perl script (see Annex 1) must be saved in the build directory and executed to patch the solutions, *.vcxproj and other required files:
cd /d %BUILDDIR%
perl vs210xfix.pl -2015
Build Apache
cd /d %BUILDDIR%
set INCLUDE=%INCLUDE%;%BUILDDIR%\srclib\pcre\build;%BUILDDIR%\srclib\zlib;%BUILDDIR%\srclib\libxml2\include;%BUILDDIR%\srclib\apr-iconv\lib;%BUILDDIR%\srclib\apr-iconv\include
set LIB=%LIB%;%BUILDDIR%\srclib\apr\libR;%BUILDDIR%\srclib\pcre\build;%BUILDDIR%\srclib\zlib;%BUILDDIR%\srclib\libxml2\lib
Build from command line
devenv Apache.sln /useenv /build "Release|x64" /Project libapr
Clean up the debug symbol files:
del /F /S /Q /A "\Apache24\*.pdb"
Build from Visual Studio
devenv Apache.sln /useenv
1. Right click on the Apache solution, click on Configuration Manager and select for Active solution configuration: Release and for Active solution platform: x64
2. Right click on InstallBin and select Build.
If the build was successful, the files will be installed in \Apache24. While this path can be changed, it is not recommended as it is hardcoded in many config and makefiles.
Clean up the debug symbol files:
Deploy
Deploying Apache httpd binaries means archiving the entire \Apache24 folder and shipping it to another machine.
Also, the x64 Visual C++ redistributable libraries must be installed on the target machine:
Apache httpd can be installed as a Windows service:
\Apache24\bin\httpd.exe -k install
Then use \Apache24\bin\ApacheMonitor.exe to stop/start the service.
Annex 1 - vs210xfix.pl
#!/usr/bin/perl
##############################################################################
# vs201xfix.pl, version: 1.0.20160318 (c) Cristian Chiru <cristian.chiru@dcsi.eu>
##############################################################################
# This script will add the missing x64 build profiles from the upgraded
# Apache HTTPD projects. It is designed to work with the newer VS project
# formats that are XML based, not the old .dsp.
# You will still need to run "perl srclib\apr\build\lineends.pl --force"
# and "perl srclib\apr\build\cvtdsp.pl -2005", then upgrade the .dsp
# projects in VS 201x before running this script.
##############################################################################
use strict;
use warnings FATAL => 'all';
use XML::Simple qw(:strict);
use Data::Dumper;
use Storable qw( dclone );
use IO::File;
use File::Copy;
use File::Find;
$ARGV[0] //= '-h';
my @SOLUTIONCONF = qw(Release Debug);
my $ARCH = 'x64';
my %GLOBAL_VARS;
$GLOBAL_VARS{'ver'} = substr( $ARGV[0], 1 ) if ($ARGV[0] ne '');
$GLOBAL_VARS{'backup_ext'} = '.~';
if ($GLOBAL_VARS{'ver'} eq '2013') {
$GLOBAL_VARS{'ext'} = '.vcproj';
$GLOBAL_VARS{'toolset'} = 'v120';
find( \&fixVS, '.' );
} elsif ($GLOBAL_VARS{'ver'} eq '2015') {
$GLOBAL_VARS{'ext'} = '.vcxproj';
$GLOBAL_VARS{'toolset'} = 'v140';
find( \&fixVS, '.' );
} elsif ($GLOBAL_VARS{'ver'} eq 'rollback') {
find( \&rollback, '.' );
} else {
print "Parameters:\n";
print "-2013\t Fix Visual Studio 2013 projects !!Not tested yet!!\n";
print "-2015\t Fix Visual Studio 2015 projects\n";
print "-source\t Fix the .C/.H source files !!Experimental!!\n";
print "-rollback\t Restore from backup files\n";
die "[ERROR] Invalid or missing argument";
}
# Main sub for changing the VC files
sub fixVS {
my $fname = $_;
if ($fname =~ m/(?:$GLOBAL_VARS{ext}|\.sln|ApacheMonitor\.r*c|modules\.mk\.win|encoding\.h|Makefile\.win|\.mak)$/) {
print $File::Find::dir."\\$fname\n";
# Rollback first the backup, to ensure always have the originals as a starting point. May be removed later on.
rollback( $fname.$GLOBAL_VARS{'backup_ext'} );
copy( $fname, $fname.$GLOBAL_VARS{'backup_ext'} ) || die $!;
}
# Cleanup cache and generated files
unlink $fname if ($fname =~ m/\.(suo|sdf|idb|log)$/);
my $changed;
# Experimental: try to fix source code for x64 platform
# if ($fname =~ m/\.[ch]$/) {
# $changed = patchFile ( $fname, [
# [ '\b(?:int|unsigned\s+long)\b', '__int64' ],
# [ '\blong\s+__int64\b', 'long int' ],
# [ '\bunsigned\s+int\b', 'unsigned __int64' ]
# ] );
# }
# Fix ApacheMonitor
if ($fname eq 'ApacheMonitor.c') {
$changed = patchFile ( $fname, [
[ '\_setargv\(\);', '//_setargv();' ]
] );
}
if ($fname eq 'ApacheMonitor.rc') {
$changed = patchFile ( $fname, [
[ '^.*ApacheMonitor\.manifest.*$', '' ]
] );
}
# Fix modules.mk.win to build libapriconv_ces_modules
if ($fname eq 'modules.mk.win') {
$changed = patchFile ( $fname, [
[ '\/Y[cu]iconv\.h', '' ],
[ $ARCH.'\\\\', '' ]
] );
}
if ($fname =~ m/(Makefile.win|\.mak)$/) {
$changed = patchFile ( $fname, [
[ $ARCH.'\\\\', '' ]
] );
}
if ($fname eq 'encoding.h') {
$changed = patchFile ( $fname, [
[ '(^\s*iconv_t\s+iconv_.*)', sub {"//$1"} ]
] );
}
# Fix the Solution
if ($fname =~ m/\.sln$/) {
$changed = patchSLN( $fname );
}
# Fix the projects
elsif ($fname =~ m/$GLOBAL_VARS{ext}$/) {
$changed = 0;
# Perform the preliminary path using simple line by line replace
my @results = grepFile( $fname, '\|x64' );
my $rescount = scalar @results;
# If the project does not containg x64 config
if ($rescount < 1) {
$changed = patchFile ( $fname, [
[ '\|Win32', '|'.$ARCH ],
[ '<(TargetEnvironment|Platform)>Win32', sub {"<$1>$ARCH"} ]
] );
}
# Still, there are some changes that apply to all projects
$changed = patchFile ( $fname, [
[ '<(IntDir|OutDir|TargetName)>.*$', '' ],
#[ '<(OutputFile)>.*\\\([^<]+)', sub { "<$1>$2"} ],
[ $ARCH.'\\\\', '' ]
] );
# Parse the xml for advanced editing
my $xml = XML::Simple->new(
AttrIndent => 0,
Cache => 'memshare',
ContentKey => '-content',
ForceArray => 1,
KeepRoot => 1,
KeyAttr => [ ],
NoEscape => 0,
NoSort => 1,
XMLDecl => '<?xml version="1.0" encoding="utf-8"?>'
);
my $data = $xml->XMLin( $fname );
#print "**DEBUG** ".Dumper($data)."\n";
patchXML( $data );
if ($data) {
my $at_the_end = delete $data->{Project}->[0]->{Import};
# Output the XML data
my $parsedxml = $xml->XMLout( $data );
my $outfile = new IO::File ( $fname, "w" ) || die $!;
print $outfile $parsedxml;
undef $outfile;
# Since XML::Simple does not maintain the order of the elements in the ouput, and OF COURSE that
# it matters in the VS project files... we have to move the <Import> tags to the end
postpatchXML( $fname, $at_the_end );
$changed = 1;
}
}
if ($changed) {
print "\n\tPrepared for VS $GLOBAL_VARS{'ver'}\n";
}
elsif (defined $changed) {
print "\n\t[NOTHING], deleting backup ... ";
unlink $fname.$GLOBAL_VARS{'backup_ext'} || die $!;
print "done.\n";
}
}
sub patchSLN {
my ($fname) = @_;
my @projects;
my $section = '';
my $tname = $fname.'.#';
my $srcfl = new IO::File $fname, "r" || die $!;
my $dstfl = new IO::File $tname, "w" || die $!;
# Get first some prerequisite objects
my $project_deps = "\tProjectSection(ProjectDependencies) = postProject\n";
for my $ret (grep {/Project\("\{.*\}"\)\s*=\s*"libapr"/} <$srcfl>) {
$project_deps .= "\t\t$1 = $1\n" if ($ret =~ m/,\s+"({.*})"$/);
}
$project_deps .= "\tEndProjectSection\n";
# Process the file
seek ( $srcfl, 0, 0 );
my $canwrite = 1;
while (my $src = <$srcfl>) {
my $project_name = '';
if ($src =~ m/^Project.+?\=\s+"([^"]+)",.*({[^}]+})"$/) {
$project_name = $1;
print ".";
# We exclude some of the projects from solution build - not actually needed?
#push ( @projects, [ $pguid, (($src !~ m/(?=apr\_dbd\_.|apr\_ldap)/) ? '1' : '0') ] );
push ( @projects, [ $2, '1' ] );
}
if (($src =~ m/= (preSolution|postSolution)$/) && ($src !~ m/GlobalSection\(SolutionProperties\)/)) {
$section = $1;
}
if ($src =~ m/EndGlobalSection$/) {
$canwrite = 1;
$section = '';
}
if ($canwrite == 1) {
print $dstfl $src;
if ($project_name =~ m/((Install|Build)Bin|BuildAll)/) {
print $dstfl $project_deps;
}
} elsif ($canwrite == 2) {
foreach (@SOLUTIONCONF) {
print $dstfl "\t\t$_|$ARCH = $_|$ARCH\n";
}
$canwrite = 0;
} elsif ($canwrite == 3) {
for my $prj (@projects) {
foreach (@SOLUTIONCONF) {
print $dstfl "\t\t$$prj[0].$_|$ARCH.ActiveCfg = $_|$ARCH\n";
print $dstfl "\t\t$$prj[0].$_|$ARCH.Build.0 = $_|$ARCH\n" if ($$prj[1]);
}
}
$canwrite = 0;
}
$canwrite = 2 if (($section eq 'preSolution') && ($canwrite != 0));
$canwrite = 3 if (($section eq 'postSolution') && ($canwrite != 0));
}
undef $srcfl;
undef $dstfl;
move ( $tname, $fname );
return 1;
}
sub patchXML {
# Set the PlatformToolset
for my $pg (@{$_[0]->{Project}->[0]->{PropertyGroup}}) {
if ((($pg->{Label} // '') eq 'Configuration') && (($pg->{PlatformToolset}->[0] // '') ne $GLOBAL_VARS{'toolset'})) {
$pg->{PlatformToolset}->[0] = $GLOBAL_VARS{'toolset'};
}
}
# Check the $ARCH Platform for all sections in the project file
toNewArch( $_[0]->{Project}->[0]->{ItemGroup}->[0]->{ProjectConfiguration},
'Include',
{ '' => [ '',
{
Include => [ \®ex_replace, [ 'Win32', $ARCH ] ],
Platform => [ $ARCH ]
}
]
}
);
toNewArch( $_[0]->{Project}->[0]->{PropertyGroup},
'Condition',
{ '' => [ '',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
],
Label => [ 'Configuration',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ],
PlatformToolset => [ $GLOBAL_VARS{'toolset'} ]
}
]
}
);
toNewArch( $_[0]->{Project}->[0]->{ImportGroup},
'Condition',
{ Label => [ 'PropertySheets',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
]
} );
toNewArch( $_[0]->{Project}->[0]->{ItemDefinitionGroup},
'Condition',
{ '' => [ '',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
],
ClCompile => [ '',
{
MultiProcessorCompilation => [ 'true' ]
}
]
} );
# Adjust the TargetName and output directories in all configurations
foreach my $sol (@SOLUTIONCONF) {
for my $itg (@{$_[0]->{Project}->[0]->{ItemDefinitionGroup}}) {
if ((($itg->{Condition} // '') =~ m/$sol\|$ARCH/i) && (($itg->{Label} // '') eq '')) {
#$itg->{ClCompile}->[0]->{MultiProcessorCompilation} = [ 'true' ];
$itg->{ClCompile}->[0]->{DisableSpecificWarnings} = [ '4018;4090;4101;4244;4267;4311;4312;4996' ];
$itg->{ClCompile}->[0]->{MinimalRebuild} = [ 'true' ];
my $src = ($itg->{Lib}->[0]->{OutputFile}->[0] // $itg->{Link}->[0]->{OutputFile}->[0]);
my ($path, $file) = ( $1, $2 ) if (($src // '') =~ m/(.*?)([^\\]+?)(?:\.[^.]*$|$)/);
for my $pg (@{$_[0]->{Project}->[0]->{PropertyGroup}}) {
if ((($pg->{Condition} // '') =~ m/$sol\|$ARCH/i) && (($pg->{Label} // '') eq '')) {
$pg->{TargetName} = [ $file ] if (defined $file);
$pg->{IntDir} = [ "$path\$(*B)\\" ] if (defined $path);
$pg->{OutDir} = [ "$path" ] if (defined $path);
print( "." );
last;
}
}
last;
}
}
}
}
sub postpatchXML {
my ($fname, $elements) = @_;
open my $in, '<', $fname or die "Can't read old file: $!";
open my $out, '>', "$fname.#" or die "Can't write new file: $!";
while( <$in> ) {
if (m/^<\/Project>$/) {
for my $element (@$elements) {
print $out " <Import Project=\"".$element->{Project}."\" />\n";
print( "." );
}
}
print $out $_;
}
close $out;
close $in;
move ( $fname.".#", $fname ) || die $!;
}
sub patchFile {
my ($fname, $params) = @_;
my $changed = 0;
open my $in, '<', $fname or die "Can't read old file: $!";
open my $out, '>', "$fname.#" or die "Can't write new file: $!";
while( <$in> ) {
for my $par (@$params) {
print Dumper( $par ) if ($fname eq 'libapr.vxproj');
if (m/@$par[0]/) {
my $p = @$par[1];
if (ref( $p ) eq 'CODE') {
s/@$par[0]/&$p/eg;
}
else {
s/@$par[0]/$p/g;
}
print ".";
$changed = 1;
}
}
print $out $_;
}
close $out;
close $in;
move ( $fname.".#", $fname ) || die $!;
return $changed;
}
sub toNewArch {
my ($conf, $main_key, $inout_map) = @_;
$inout_map //= { '' => [ '', { } ] };
foreach (@SOLUTIONCONF) {
while (my ($ioKey, $ioVal) = each %$inout_map) {
my $newarch_present = 0;
my $win32conf;
for my $pc (@$conf) {
if (($pc->{$ioKey} // '') eq $ioVal->[0]) {
$win32conf = $pc if (($pc->{$main_key} // '') =~ m/$_\|Win32/i);
$newarch_present = 1 if (($pc->{$main_key} // '') =~ m/$_\|$ARCH/i);
}
}
# Clone the 32 variant if we do not find the new arch
if (!$newarch_present && $win32conf) {
my $i = push ( @$conf, dclone( $win32conf ) ) - 1;
while (my ($k, $v) = each %{$ioVal->[1]}) {
#print Dumper (@$conf[$i]->{$k});
if ((ref( $v ) eq 'ARRAY') && (ref( $v->[0] ) eq 'CODE')) {
# If the first member of the array is ref to a sub,
# we pass as first argument the value of the conf and
# as 2nd parameter the array containing the sub parameters
@$conf[$i]->{$k} = $v->[0]->( @$conf[$i]->{$k}, $v->[1] );
} else {
@$conf[$i]->{$k} = $v if (@$conf[$i]->{$k});
}
print ".";
}
}
}
}
}
sub getValue {
my ($searchin, $filter, $returnfrom) = @_;
$filter //= { '' => '' };
for my $p (@$searchin) {
while (my ($ioKey, $ioVal) = each %$filter) {
print "$p = ".Dumper( $p )."\n";
if (($p->{$ioKey} // '') eq $ioVal) {
print "HOORAY!\n";
}
}
}
}
sub grepFile {
my ($fname, $params) = @_;
open my $in, '<', $fname or die "Can't read old file: $!";
my @ret = grep {/$params/} <$in>;
close $in;
return @ret;
}
sub regex_replace {
my ($content, $params) = @_;
$content =~ s/$params->[0]/$params->[1]/;
return $content;
}
sub rollback {
my ($fname) = @_;
$fname //= '';
if (($fname =~ m/$GLOBAL_VARS{'backup_ext'}$/) && (-e $fname)) {
$fname =~ s/$GLOBAL_VARS{'backup_ext'}$//;
print "\tRestoring $fname ... ";
if (move( $fname.$GLOBAL_VARS{backup_ext}, $fname )) {
print "done.\n";
} else {
print "$!\n";
}
}
}
##############################################################################
# vs201xfix.pl, version: 1.0.20160318 (c) Cristian Chiru <cristian.chiru@dcsi.eu>
##############################################################################
# This script will add the missing x64 build profiles from the upgraded
# Apache HTTPD projects. It is designed to work with the newer VS project
# formats that are XML based, not the old .dsp.
# You will still need to run "perl srclib\apr\build\lineends.pl --force"
# and "perl srclib\apr\build\cvtdsp.pl -2005", then upgrade the .dsp
# projects in VS 201x before running this script.
##############################################################################
use strict;
use warnings FATAL => 'all';
use XML::Simple qw(:strict);
use Data::Dumper;
use Storable qw( dclone );
use IO::File;
use File::Copy;
use File::Find;
$ARGV[0] //= '-h';
my @SOLUTIONCONF = qw(Release Debug);
my $ARCH = 'x64';
my %GLOBAL_VARS;
$GLOBAL_VARS{'ver'} = substr( $ARGV[0], 1 ) if ($ARGV[0] ne '');
$GLOBAL_VARS{'backup_ext'} = '.~';
if ($GLOBAL_VARS{'ver'} eq '2013') {
$GLOBAL_VARS{'ext'} = '.vcproj';
$GLOBAL_VARS{'toolset'} = 'v120';
find( \&fixVS, '.' );
} elsif ($GLOBAL_VARS{'ver'} eq '2015') {
$GLOBAL_VARS{'ext'} = '.vcxproj';
$GLOBAL_VARS{'toolset'} = 'v140';
find( \&fixVS, '.' );
} elsif ($GLOBAL_VARS{'ver'} eq 'rollback') {
find( \&rollback, '.' );
} else {
print "Parameters:\n";
print "-2013\t Fix Visual Studio 2013 projects !!Not tested yet!!\n";
print "-2015\t Fix Visual Studio 2015 projects\n";
print "-source\t Fix the .C/.H source files !!Experimental!!\n";
print "-rollback\t Restore from backup files\n";
die "[ERROR] Invalid or missing argument";
}
# Main sub for changing the VC files
sub fixVS {
my $fname = $_;
if ($fname =~ m/(?:$GLOBAL_VARS{ext}|\.sln|ApacheMonitor\.r*c|modules\.mk\.win|encoding\.h|Makefile\.win|\.mak)$/) {
print $File::Find::dir."\\$fname\n";
# Rollback first the backup, to ensure always have the originals as a starting point. May be removed later on.
rollback( $fname.$GLOBAL_VARS{'backup_ext'} );
copy( $fname, $fname.$GLOBAL_VARS{'backup_ext'} ) || die $!;
}
# Cleanup cache and generated files
unlink $fname if ($fname =~ m/\.(suo|sdf|idb|log)$/);
my $changed;
# Experimental: try to fix source code for x64 platform
# if ($fname =~ m/\.[ch]$/) {
# $changed = patchFile ( $fname, [
# [ '\b(?:int|unsigned\s+long)\b', '__int64' ],
# [ '\blong\s+__int64\b', 'long int' ],
# [ '\bunsigned\s+int\b', 'unsigned __int64' ]
# ] );
# }
# Fix ApacheMonitor
if ($fname eq 'ApacheMonitor.c') {
$changed = patchFile ( $fname, [
[ '\_setargv\(\);', '//_setargv();' ]
] );
}
if ($fname eq 'ApacheMonitor.rc') {
$changed = patchFile ( $fname, [
[ '^.*ApacheMonitor\.manifest.*$', '' ]
] );
}
# Fix modules.mk.win to build libapriconv_ces_modules
if ($fname eq 'modules.mk.win') {
$changed = patchFile ( $fname, [
[ '\/Y[cu]iconv\.h', '' ],
[ $ARCH.'\\\\', '' ]
] );
}
if ($fname =~ m/(Makefile.win|\.mak)$/) {
$changed = patchFile ( $fname, [
[ $ARCH.'\\\\', '' ]
] );
}
if ($fname eq 'encoding.h') {
$changed = patchFile ( $fname, [
[ '(^\s*iconv_t\s+iconv_.*)', sub {"//$1"} ]
] );
}
# Fix the Solution
if ($fname =~ m/\.sln$/) {
$changed = patchSLN( $fname );
}
# Fix the projects
elsif ($fname =~ m/$GLOBAL_VARS{ext}$/) {
$changed = 0;
# Perform the preliminary path using simple line by line replace
my @results = grepFile( $fname, '\|x64' );
my $rescount = scalar @results;
# If the project does not containg x64 config
if ($rescount < 1) {
$changed = patchFile ( $fname, [
[ '\|Win32', '|'.$ARCH ],
[ '<(TargetEnvironment|Platform)>Win32', sub {"<$1>$ARCH"} ]
] );
}
# Still, there are some changes that apply to all projects
$changed = patchFile ( $fname, [
[ '<(IntDir|OutDir|TargetName)>.*$', '' ],
#[ '<(OutputFile)>.*\\\([^<]+)', sub { "<$1>$2"} ],
[ $ARCH.'\\\\', '' ]
] );
# Parse the xml for advanced editing
my $xml = XML::Simple->new(
AttrIndent => 0,
Cache => 'memshare',
ContentKey => '-content',
ForceArray => 1,
KeepRoot => 1,
KeyAttr => [ ],
NoEscape => 0,
NoSort => 1,
XMLDecl => '<?xml version="1.0" encoding="utf-8"?>'
);
my $data = $xml->XMLin( $fname );
#print "**DEBUG** ".Dumper($data)."\n";
patchXML( $data );
if ($data) {
my $at_the_end = delete $data->{Project}->[0]->{Import};
# Output the XML data
my $parsedxml = $xml->XMLout( $data );
my $outfile = new IO::File ( $fname, "w" ) || die $!;
print $outfile $parsedxml;
undef $outfile;
# Since XML::Simple does not maintain the order of the elements in the ouput, and OF COURSE that
# it matters in the VS project files... we have to move the <Import> tags to the end
postpatchXML( $fname, $at_the_end );
$changed = 1;
}
}
if ($changed) {
print "\n\tPrepared for VS $GLOBAL_VARS{'ver'}\n";
}
elsif (defined $changed) {
print "\n\t[NOTHING], deleting backup ... ";
unlink $fname.$GLOBAL_VARS{'backup_ext'} || die $!;
print "done.\n";
}
}
sub patchSLN {
my ($fname) = @_;
my @projects;
my $section = '';
my $tname = $fname.'.#';
my $srcfl = new IO::File $fname, "r" || die $!;
my $dstfl = new IO::File $tname, "w" || die $!;
# Get first some prerequisite objects
my $project_deps = "\tProjectSection(ProjectDependencies) = postProject\n";
for my $ret (grep {/Project\("\{.*\}"\)\s*=\s*"libapr"/} <$srcfl>) {
$project_deps .= "\t\t$1 = $1\n" if ($ret =~ m/,\s+"({.*})"$/);
}
$project_deps .= "\tEndProjectSection\n";
# Process the file
seek ( $srcfl, 0, 0 );
my $canwrite = 1;
while (my $src = <$srcfl>) {
my $project_name = '';
if ($src =~ m/^Project.+?\=\s+"([^"]+)",.*({[^}]+})"$/) {
$project_name = $1;
print ".";
# We exclude some of the projects from solution build - not actually needed?
#push ( @projects, [ $pguid, (($src !~ m/(?=apr\_dbd\_.|apr\_ldap)/) ? '1' : '0') ] );
push ( @projects, [ $2, '1' ] );
}
if (($src =~ m/= (preSolution|postSolution)$/) && ($src !~ m/GlobalSection\(SolutionProperties\)/)) {
$section = $1;
}
if ($src =~ m/EndGlobalSection$/) {
$canwrite = 1;
$section = '';
}
if ($canwrite == 1) {
print $dstfl $src;
if ($project_name =~ m/((Install|Build)Bin|BuildAll)/) {
print $dstfl $project_deps;
}
} elsif ($canwrite == 2) {
foreach (@SOLUTIONCONF) {
print $dstfl "\t\t$_|$ARCH = $_|$ARCH\n";
}
$canwrite = 0;
} elsif ($canwrite == 3) {
for my $prj (@projects) {
foreach (@SOLUTIONCONF) {
print $dstfl "\t\t$$prj[0].$_|$ARCH.ActiveCfg = $_|$ARCH\n";
print $dstfl "\t\t$$prj[0].$_|$ARCH.Build.0 = $_|$ARCH\n" if ($$prj[1]);
}
}
$canwrite = 0;
}
$canwrite = 2 if (($section eq 'preSolution') && ($canwrite != 0));
$canwrite = 3 if (($section eq 'postSolution') && ($canwrite != 0));
}
undef $srcfl;
undef $dstfl;
move ( $tname, $fname );
return 1;
}
sub patchXML {
# Set the PlatformToolset
for my $pg (@{$_[0]->{Project}->[0]->{PropertyGroup}}) {
if ((($pg->{Label} // '') eq 'Configuration') && (($pg->{PlatformToolset}->[0] // '') ne $GLOBAL_VARS{'toolset'})) {
$pg->{PlatformToolset}->[0] = $GLOBAL_VARS{'toolset'};
}
}
# Check the $ARCH Platform for all sections in the project file
toNewArch( $_[0]->{Project}->[0]->{ItemGroup}->[0]->{ProjectConfiguration},
'Include',
{ '' => [ '',
{
Include => [ \®ex_replace, [ 'Win32', $ARCH ] ],
Platform => [ $ARCH ]
}
]
}
);
toNewArch( $_[0]->{Project}->[0]->{PropertyGroup},
'Condition',
{ '' => [ '',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
],
Label => [ 'Configuration',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ],
PlatformToolset => [ $GLOBAL_VARS{'toolset'} ]
}
]
}
);
toNewArch( $_[0]->{Project}->[0]->{ImportGroup},
'Condition',
{ Label => [ 'PropertySheets',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
]
} );
toNewArch( $_[0]->{Project}->[0]->{ItemDefinitionGroup},
'Condition',
{ '' => [ '',
{
Condition => [ \®ex_replace, [ 'Win32', $ARCH ] ]
}
],
ClCompile => [ '',
{
MultiProcessorCompilation => [ 'true' ]
}
]
} );
# Adjust the TargetName and output directories in all configurations
foreach my $sol (@SOLUTIONCONF) {
for my $itg (@{$_[0]->{Project}->[0]->{ItemDefinitionGroup}}) {
if ((($itg->{Condition} // '') =~ m/$sol\|$ARCH/i) && (($itg->{Label} // '') eq '')) {
#$itg->{ClCompile}->[0]->{MultiProcessorCompilation} = [ 'true' ];
$itg->{ClCompile}->[0]->{DisableSpecificWarnings} = [ '4018;4090;4101;4244;4267;4311;4312;4996' ];
$itg->{ClCompile}->[0]->{MinimalRebuild} = [ 'true' ];
my $src = ($itg->{Lib}->[0]->{OutputFile}->[0] // $itg->{Link}->[0]->{OutputFile}->[0]);
my ($path, $file) = ( $1, $2 ) if (($src // '') =~ m/(.*?)([^\\]+?)(?:\.[^.]*$|$)/);
for my $pg (@{$_[0]->{Project}->[0]->{PropertyGroup}}) {
if ((($pg->{Condition} // '') =~ m/$sol\|$ARCH/i) && (($pg->{Label} // '') eq '')) {
$pg->{TargetName} = [ $file ] if (defined $file);
$pg->{IntDir} = [ "$path\$(*B)\\" ] if (defined $path);
$pg->{OutDir} = [ "$path" ] if (defined $path);
print( "." );
last;
}
}
last;
}
}
}
}
sub postpatchXML {
my ($fname, $elements) = @_;
open my $in, '<', $fname or die "Can't read old file: $!";
open my $out, '>', "$fname.#" or die "Can't write new file: $!";
while( <$in> ) {
if (m/^<\/Project>$/) {
for my $element (@$elements) {
print $out " <Import Project=\"".$element->{Project}."\" />\n";
print( "." );
}
}
print $out $_;
}
close $out;
close $in;
move ( $fname.".#", $fname ) || die $!;
}
sub patchFile {
my ($fname, $params) = @_;
my $changed = 0;
open my $in, '<', $fname or die "Can't read old file: $!";
open my $out, '>', "$fname.#" or die "Can't write new file: $!";
while( <$in> ) {
for my $par (@$params) {
print Dumper( $par ) if ($fname eq 'libapr.vxproj');
if (m/@$par[0]/) {
my $p = @$par[1];
if (ref( $p ) eq 'CODE') {
s/@$par[0]/&$p/eg;
}
else {
s/@$par[0]/$p/g;
}
print ".";
$changed = 1;
}
}
print $out $_;
}
close $out;
close $in;
move ( $fname.".#", $fname ) || die $!;
return $changed;
}
sub toNewArch {
my ($conf, $main_key, $inout_map) = @_;
$inout_map //= { '' => [ '', { } ] };
foreach (@SOLUTIONCONF) {
while (my ($ioKey, $ioVal) = each %$inout_map) {
my $newarch_present = 0;
my $win32conf;
for my $pc (@$conf) {
if (($pc->{$ioKey} // '') eq $ioVal->[0]) {
$win32conf = $pc if (($pc->{$main_key} // '') =~ m/$_\|Win32/i);
$newarch_present = 1 if (($pc->{$main_key} // '') =~ m/$_\|$ARCH/i);
}
}
# Clone the 32 variant if we do not find the new arch
if (!$newarch_present && $win32conf) {
my $i = push ( @$conf, dclone( $win32conf ) ) - 1;
while (my ($k, $v) = each %{$ioVal->[1]}) {
#print Dumper (@$conf[$i]->{$k});
if ((ref( $v ) eq 'ARRAY') && (ref( $v->[0] ) eq 'CODE')) {
# If the first member of the array is ref to a sub,
# we pass as first argument the value of the conf and
# as 2nd parameter the array containing the sub parameters
@$conf[$i]->{$k} = $v->[0]->( @$conf[$i]->{$k}, $v->[1] );
} else {
@$conf[$i]->{$k} = $v if (@$conf[$i]->{$k});
}
print ".";
}
}
}
}
}
sub getValue {
my ($searchin, $filter, $returnfrom) = @_;
$filter //= { '' => '' };
for my $p (@$searchin) {
while (my ($ioKey, $ioVal) = each %$filter) {
print "$p = ".Dumper( $p )."\n";
if (($p->{$ioKey} // '') eq $ioVal) {
print "HOORAY!\n";
}
}
}
}
sub grepFile {
my ($fname, $params) = @_;
open my $in, '<', $fname or die "Can't read old file: $!";
my @ret = grep {/$params/} <$in>;
close $in;
return @ret;
}
sub regex_replace {
my ($content, $params) = @_;
$content =~ s/$params->[0]/$params->[1]/;
return $content;
}
sub rollback {
my ($fname) = @_;
$fname //= '';
if (($fname =~ m/$GLOBAL_VARS{'backup_ext'}$/) && (-e $fname)) {
$fname =~ s/$GLOBAL_VARS{'backup_ext'}$//;
print "\tRestoring $fname ... ";
if (move( $fname.$GLOBAL_VARS{backup_ext}, $fname )) {
print "done.\n";
} else {
print "$!\n";
}
}
}
Sign up here with your email
2 comments
Write commentsHello,
ReplyI want to build the apache for my project using vs2013 and I've some extra dependent components which needs to be compiled Please help me to compile it.
lua
nghttp2
apr
apr-util
remaining components are common.
Best Regards,
Satish
Hi Satish,
Replyapr and apr-util are already included in the apr iconv and deps packages.
Compiling lua or nghttp2 is specific to these individual project. Each should have a readme about building for MSWIN. As you can see in the article, each dependent projects must be built in different ways:
- PCRE with CMAKE
- ZLIB with NMAKE
- OPENSSL has a perl script to build the make files to build with NMAKE.
So it really comes down to specifics to each project. If there are no NMAKE makefiles or you cannot generate them, then you must do it yourself i'm afraid :)
Emoticon Emoticon