Skip to content

Instantly share code, notes, and snippets.

@jay
Last active March 1, 2021 08:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jay/125191c35bbeb894444eff827651f755 to your computer and use it in GitHub Desktop.
Save jay/125191c35bbeb894444eff827651f755 to your computer and use it in GitHub Desktop.
Update curl project file templates for OpenSSL 1.1.x
#!/usr/bin/env perl
=begin comment
README
./change_openssl_lib_names.pl
This script was written to update Windows project file templates in the curl
repo. It changes the OpenSSL libnames from 1.0.x to 1.1.x:
libeay32.lib -> libcrypto.lib
ssleay32.lib -> libssl.lib
Also, this script changes the include directory and adds the directory that
contains the libs to the list of include directories, before the standard
openssl include directory. That is because each individual OpenSSL
configuration that is built and has its own set of libs now has its own include
directory from the build as well. The source-located openssl include directory
only holds the opensslconf.h from the most recent build, which is not
necessarily the same for all configurations.
..\..\..\..\..\openssl\inc32 -> ..\..\..\..\..\openssl\include
And then prepend to the list:
..\..\..\..\..\openssl\build\
Win{32,64}\VC{6..15}\{DLL,LIB} {Debug,Release}\include
Refer to https://github.com/curl/curl/pull/6675
Copyright (C) 2021 Jay Satiro <raysatiro@yahoo.com>
http://curl.haxx.se/docs/copyright.html
https://gist.github.com/jay/125191c35bbeb894444eff827651f755
=end comment
=cut
use warnings;
use strict;
# oldname => newname
my %libs_original = ("libeay32.lib" => "libcrypto.lib",
"ssleay32.lib" => "libssl.lib");
# oldinc => newinc
my $oldinc_original = '..\..\..\..\..\openssl\inc32';
my $newinc_original = '..\..\..\..\..\openssl\include';
sub modify(@) {
local (*IN, *OUT);
my ($version, $infile, $outfile) = @_;
my $line;
my $linenum = 0;
my $config;
my @all;
open(IN, "<:raw", $infile) or return "Can't open $infile : $!";
open(OUT, ">:raw", $outfile) or return "Can't open $outfile : $!";
while(!eof(IN)) {
defined($line = readline(IN)) or return "Can't read $infile : $!";
$linenum++;
#
# get current configuration
#
if($version == 6) {
if($line =~ /^[ \t]*!(?:ELSE)?IF[ \t]+"\Q$(CFG)\E"[ \t]+==[ \t]+
"(?:curl|libcurl)\ -\ (Win32|x64)\ (.+)"/ix) {
$config = {};
$config->{name} = $2;
$config->{platform} = $1;
}
}
elsif($version >= 7 && $version <= 9) {
if($line =~ /^[ \t]*Name="(.+)\|(Win32|x64)"/i) {
$config = {};
$config->{name} = $1;
$config->{platform} = $2;
}
}
elsif($version >= 10) {
if($line =~ /^[ \t]*<ItemDefinitionGroup\ Condition=
"'\Q$(Configuration)|$(Platform)\E'==
'(.+)\|(Win32|x64)'">/ix) {
$config = {};
$config->{name} = $1;
$config->{platform} = $2;
}
}
# if this is a new config then make the rest of the keys
if(defined($config->{name}) && !defined($config->{linenum})) {
$config->{infile} = $infile;
$config->{linenum} = $linenum;
# The platform must be Win32 or Win64
if(lc($config->{platform}) eq "x64") {
$config->{platform} = "Win64";
}
elsif(lc($config->{platform}) ne "win32") {
return "FATAL: Unexpected platform at line $linenum in $infile : " .
"$config->{platform}";
}
# Extract OpenSSL library type, for example:
# "LIB Debug - DLL OpenSSL - DLL LibSSH2"
# static libcurl debug, dynamic openssl debug, dynamic libssh2 debug
# openssl lib type is DLL Debug
if($config->{name} =~ /^(?:DLL|LIB)\ (Debug|Release).+
(DLL|LIB)\ OpenSSL/ix) {
$config->{openssl} = "$2 $1";
#..\..\..\..\..\openssl\include\..\build\Win64\VC10\DLL Debug
($config->{ossllibdir} = $newinc_original) =~ s/^"|\\?"?$//g;
$config->{ossllibdir} .= "\\..\\build\\$config->{platform}" .
"\\VC$version\\$config->{openssl}\\include";
}
elsif($config->{name} =~ /OpenSSL/i) {
return "FATAL: Unexpected config at line $linenum in $infile : " .
"$config->{name}";
}
for my $i (0 .. $#all) {
#print "$i: $_=$all[$i]{$_}\n" for keys %{$all[$i]}; print "\n";
if(lc($config->{name}) eq lc($all[$i]{name}) &&
lc($config->{platform}) eq lc($all[$i]{platform})) {
return "FATAL: Unexpected duplicate configuration at lines " .
"$all[$i]{linenum} and $config->{linenum} in $infile : " .
"$config->{name}|$config->{platform}";
}
}
#print "$_ => $config->{$_}\n" for keys %{$config}; print "\n";
push @all, $config;
next;
}
else {
# die on unparseable config line otherwise wrong data could be changed
if($line =~ /(?:DLL|LIB) (?:Debug|Release)/i) {
if(($version == 6 && $line =~ /\Q$(CFG)\E/i) ||
($version >= 7 && $version <= 9 && $line =~ /(?<![^ \t])Name=/i) ||
($version >= 10 &&
$line =~ /ItemDefinitionGroup.+\Q$(Configuration)\E/i)) {
return "FATAL: Unparseable config at line $linenum in $infile : " .
"$line";
}
}
# skip changing lines until first config line has been parsed
next if !defined($config->{name});
}
#
# update lib names
#
while(my ($oldlib, $newlib) = each %libs_original) {
# reset $line regex prev match end pos so next m//g match starts from 0
pos($line) = undef;
$oldlib =~ s/^"|"$//g;
$newlib =~ s/^"|"$//g;
if($version == 6) {
if($newlib =~ / /) {
$newlib = "\"$newlib\"";
}
if($line =~ /^# ADD (?:BASE )?LINK32 /gi) {
$line =~ s/\G(.*?)
(
(?<=\ ) # positive lookbehind
("?)\Q$oldlib\E(\3) # oldlib may be quoted
(?=\ |\r?$) # positive lookahead
)
/$1$newlib/gix;
}
}
elsif($version >= 7 && $version <= 9) {
if($newlib =~ / /) {
$newlib = "&quot;$newlib&quot;";
}
if($line =~ /^[ \t]*AdditionalDependencies="/gi) {
$line =~ s/\G(.*?)
(
(?<=[ "])
((?:&quot;)?)\Q$oldlib\E(\3)
(?=[ "])
)
/$1$newlib/gix;
}
}
elsif($version >= 10) {
if($newlib =~ / /) {
$newlib = "\"$newlib\"";
}
if($line =~ /^[ \t]*<AdditionalDependencies>/gi) {
$line =~ s/\G(.*?)
(
(?<=[;>])
("?)\Q$oldlib\E(\3)
(?=[;<])
)
/$1$newlib/gix;
}
}
}
#
# update include directory
#
pos($line) = undef;
(my $oldinc = $oldinc_original) =~ s/^"|"$//g;
(my $newinc = $newinc_original) =~ s/^"|"$//g;
if($version == 6) {
$newinc = "\"$newinc\""; # vc6 always quotes each include directory
if($line =~ /^# ADD (?:BASE )?CPP /gi) {
$line =~ s/\G(.*?)
(
(?<=\/I\ )
("?)\Q$oldinc\E(\3)
(?=\ |\r?$)
)
/$1$newinc/gix;
}
}
elsif($version >= 7 && $version <= 9) {
my $d = (($version < 8) ? "," : ";");
if($line =~ /^[ \t]*AdditionalIncludeDirectories="/gi) {
$line =~ s/\G(.*?)
(
(?<=[$d"])
\Q$oldinc\E
(?=[$d"])
)
/$1$newinc/gix;
}
}
elsif($version >= 10) {
if($line =~ /^[ \t]*<AdditionalIncludeDirectories>/gi) {
$line =~ s/\G(.*?)
(
(?<=[;>])
\Q$oldinc\E
(?=[;<])
)
/$1$newinc/gix;
}
}
#
# prepend ossl lib dir as include dir (since it contains opensslconf.h)
#
if(defined($config->{ossllibdir})) {
my $libdir = $config->{ossllibdir};
pos($line) = undef;
if($version == 6) {
$libdir = "\"$libdir\"";
if($line =~ /^# ADD (?:BASE )?CPP /gi) {
$line =~ s/\G(.*?)
(
(?<=(?<!\/I\ \Q$libdir\E\ )\/I\ )
\Q$newinc\E
(?=\ |\r?$)
)
/$1$libdir\ \/I\ $newinc/gix;
}
}
elsif($version >= 7 && $version <= 9) {
my $d = (($version < 8) ? "," : ";");
if($line =~ /^[ \t]*AdditionalIncludeDirectories="/gi) {
$line =~ s/\G(.*?)
(
(?<=[$d"](?<!\Q$libdir\E$d))
\Q$newinc\E
(?=[$d"])
)
/$1$libdir$d$newinc/gix;
}
}
elsif($version >= 10) {
if($line =~ /^[ \t]*<AdditionalIncludeDirectories>/gi) {
$line =~ s/\G(.*?)
(
(?<=[;>](?<!\Q$libdir\E;))
\Q$newinc\E
(?=[;<])
)
/$1$libdir;$newinc/gix;
}
}
}
}
continue {
if(defined($line)) {
print OUT $line or return "Can't write $outfile : $!";
}
}
close(IN) or return "Can't close $infile : $!";
close(OUT) or return "Can't close $outfile : $!";
return undef;
}
# This is the max times to retry modifying each file.
# Modification fails if Microsoft dev git detects file changes and opens
# the file at the same time as this script is attempting to modify.
my $max_retries = 10;
for my $version (6, 7, 7.1, 8, 9, 10, 11, 12, 14, 15) {
for my $template ("src/curl.tmpl", "lib/libcurl.tmpl") {
my $infile = "curl/projects/Windows/VC$version/$template";
my $outfile = "$infile.tmp";
for(my $i = 0; $i < $max_retries; sleep($i++)) {
my $errmsg = modify($version, $infile, $outfile);
last if !defined($errmsg);
$errmsg =~ s/[\r\n]+$//g;
die $errmsg if $errmsg =~ /^FATAL: /;
die "FATAL: $errmsg" if $i+1 == $max_retries;
print STDERR "[Retrying in ${i}s] $errmsg\n";
}
for(my $i = 0; $i < $max_retries; sleep($i++)) {
my $result = rename($outfile, $infile);
last if $result;
my $errmsg = "Can't rename $outfile => $infile: $!";
die "FATAL: $errmsg" if $i+1 == $max_retries;
print STDERR "[Retrying in ${i}s] $errmsg\n";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment