1#!/usr/bin/env perl
2
3# Generate main file, individual apps and solution files for MS Visual Studio
4# 2010
5#
6# Must be run from mbedTLS root or scripts directory.
7# Takes no argument.
8#
9# Copyright The Mbed TLS Contributors
10# SPDX-License-Identifier: Apache-2.0
11#
12# Licensed under the Apache License, Version 2.0 (the "License"); you may
13# not use this file except in compliance with the License.
14# You may obtain a copy of the License at
15#
16# http://www.apache.org/licenses/LICENSE-2.0
17#
18# Unless required by applicable law or agreed to in writing, software
19# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
20# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21# See the License for the specific language governing permissions and
22# limitations under the License.
23
24use warnings;
25use strict;
26use Digest::MD5 'md5_hex';
27
28my $vsx_dir = "visualc/VS2010";
29my $vsx_ext = "vcxproj";
30my $vsx_app_tpl_file = "scripts/data_files/vs2010-app-template.$vsx_ext";
31my $vsx_main_tpl_file = "scripts/data_files/vs2010-main-template.$vsx_ext";
32my $vsx_main_file = "$vsx_dir/mbedTLS.$vsx_ext";
33my $vsx_sln_tpl_file = "scripts/data_files/vs2010-sln-template.sln";
34my $vsx_sln_file = "$vsx_dir/mbedTLS.sln";
35
36my $programs_dir = 'programs';
37my $mbedtls_header_dir = 'include/mbedtls';
38my $psa_header_dir = 'include/psa';
39my $source_dir = 'library';
40my $test_source_dir = 'tests/src';
41my $test_header_dir = 'tests/include/test';
42my $test_drivers_header_dir = 'tests/include/test/drivers';
43
44my @thirdparty_header_dirs = qw(
45    3rdparty/everest/include/everest
46);
47my @thirdparty_source_dirs = qw(
48    3rdparty/everest/library
49    3rdparty/everest/library/kremlib
50    3rdparty/everest/library/legacy
51);
52
53# Directories to add to the include path.
54# Order matters in case there are files with the same name in more than
55# one directory: the compiler will use the first match.
56my @include_directories = qw(
57    include
58    3rdparty/everest/include/
59    3rdparty/everest/include/everest
60    3rdparty/everest/include/everest/vs2010
61    3rdparty/everest/include/everest/kremlib
62    tests/include
63);
64my $include_directories = join(';', map {"../../$_"} @include_directories);
65
66# Directories to add to the include path when building the library, but not
67# when building tests or applications.
68my @library_include_directories = qw(
69    library
70);
71my $library_include_directories =
72  join(';', map {"../../$_"} (@library_include_directories,
73                              @include_directories));
74
75my @excluded_files = qw(
76    3rdparty/everest/library/Hacl_Curve25519.c
77);
78my %excluded_files = ();
79foreach (@excluded_files) { $excluded_files{$_} = 1 }
80
81# Need windows line endings!
82my $vsx_hdr_tpl = <<EOT;
83    <ClInclude Include="..\\..\\{NAME}" />\r
84EOT
85my $vsx_src_tpl = <<EOT;
86    <ClCompile Include="..\\..\\{NAME}" />\r
87EOT
88
89my $vsx_sln_app_entry_tpl = <<EOT;
90Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "{APPNAME}", "{APPNAME}.vcxproj", "{GUID}"\r
91	ProjectSection(ProjectDependencies) = postProject\r
92		{46CF2D25-6A36-4189-B59C-E4815388E554} = {46CF2D25-6A36-4189-B59C-E4815388E554}\r
93	EndProjectSection\r
94EndProject\r
95EOT
96
97my $vsx_sln_conf_entry_tpl = <<EOT;
98		{GUID}.Debug|Win32.ActiveCfg = Debug|Win32\r
99		{GUID}.Debug|Win32.Build.0 = Debug|Win32\r
100		{GUID}.Debug|x64.ActiveCfg = Debug|x64\r
101		{GUID}.Debug|x64.Build.0 = Debug|x64\r
102		{GUID}.Release|Win32.ActiveCfg = Release|Win32\r
103		{GUID}.Release|Win32.Build.0 = Release|Win32\r
104		{GUID}.Release|x64.ActiveCfg = Release|x64\r
105		{GUID}.Release|x64.Build.0 = Release|x64\r
106EOT
107
108exit( main() );
109
110sub check_dirs {
111    foreach my $d (@thirdparty_header_dirs, @thirdparty_source_dirs) {
112        if (not (-d $d)) { return 0; }
113    }
114    return -d $vsx_dir
115        && -d $mbedtls_header_dir
116        && -d $psa_header_dir
117        && -d $source_dir
118        && -d $test_source_dir
119        && -d $test_header_dir
120        && -d $test_drivers_header_dir
121        && -d $programs_dir;
122}
123
124sub slurp_file {
125    my ($filename) = @_;
126
127    local $/ = undef;
128    open my $fh, '<', $filename or die "Could not read $filename\n";
129    my $content = <$fh>;
130    close $fh;
131
132    return $content;
133}
134
135sub content_to_file {
136    my ($content, $filename) = @_;
137
138    open my $fh, '>', $filename or die "Could not write to $filename\n";
139    print $fh $content;
140    close $fh;
141}
142
143sub gen_app_guid {
144    my ($path) = @_;
145
146    my $guid = md5_hex( "mbedTLS:$path" );
147    $guid =~ s/(.{8})(.{4})(.{4})(.{4})(.{12})/\U{$1-$2-$3-$4-$5}/;
148
149    return $guid;
150}
151
152sub gen_app {
153    my ($path, $template, $dir, $ext) = @_;
154
155    my $guid = gen_app_guid( $path );
156    $path =~ s!/!\\!g;
157    (my $appname = $path) =~ s/.*\\//;
158
159    my $srcs = "<ClCompile Include=\"..\\..\\programs\\$path.c\" \/>";
160    if( $appname eq "ssl_client2" or $appname eq "ssl_server2" or
161        $appname eq "query_compile_time_config" ) {
162        $srcs .= "\r\n    <ClCompile Include=\"..\\..\\programs\\test\\query_config.c\" \/>";
163    }
164
165    my $content = $template;
166    $content =~ s/<SOURCES>/$srcs/g;
167    $content =~ s/<APPNAME>/$appname/g;
168    $content =~ s/<GUID>/$guid/g;
169    $content =~ s/INCLUDE_DIRECTORIES\r\n/$include_directories/g;
170
171    content_to_file( $content, "$dir/$appname.$ext" );
172}
173
174sub get_app_list {
175    my $app_list = `cd $programs_dir && make list`;
176    die "make list failed: $!\n" if $?;
177
178    return split /\s+/, $app_list;
179}
180
181sub gen_app_files {
182    my @app_list = @_;
183
184    my $vsx_tpl = slurp_file( $vsx_app_tpl_file );
185
186    for my $app ( @app_list ) {
187        gen_app( $app, $vsx_tpl, $vsx_dir, $vsx_ext );
188    }
189}
190
191sub gen_entry_list {
192    my ($tpl, @names) = @_;
193
194    my $entries;
195    for my $name (@names) {
196        (my $entry = $tpl) =~ s/{NAME}/$name/g;
197        $entries .= $entry;
198    }
199
200    return $entries;
201}
202
203sub gen_main_file {
204    my ($headers, $sources,
205        $hdr_tpl, $src_tpl,
206        $main_tpl, $main_out) = @_;
207
208    my $header_entries = gen_entry_list( $hdr_tpl, @$headers );
209    my $source_entries = gen_entry_list( $src_tpl, @$sources );
210
211    my $out = slurp_file( $main_tpl );
212    $out =~ s/SOURCE_ENTRIES\r\n/$source_entries/m;
213    $out =~ s/HEADER_ENTRIES\r\n/$header_entries/m;
214    $out =~ s/INCLUDE_DIRECTORIES\r\n/$library_include_directories/g;
215
216    content_to_file( $out, $main_out );
217}
218
219sub gen_vsx_solution {
220    my (@app_names) = @_;
221
222    my ($app_entries, $conf_entries);
223    for my $path (@app_names) {
224        my $guid = gen_app_guid( $path );
225        (my $appname = $path) =~ s!.*/!!;
226
227        my $app_entry = $vsx_sln_app_entry_tpl;
228        $app_entry =~ s/{APPNAME}/$appname/g;
229        $app_entry =~ s/{GUID}/$guid/g;
230
231        $app_entries .= $app_entry;
232
233        my $conf_entry = $vsx_sln_conf_entry_tpl;
234        $conf_entry =~ s/{GUID}/$guid/g;
235
236        $conf_entries .= $conf_entry;
237    }
238
239    my $out = slurp_file( $vsx_sln_tpl_file );
240    $out =~ s/APP_ENTRIES\r\n/$app_entries/m;
241    $out =~ s/CONF_ENTRIES\r\n/$conf_entries/m;
242
243    content_to_file( $out, $vsx_sln_file );
244}
245
246sub del_vsx_files {
247    unlink glob "'$vsx_dir/*.$vsx_ext'";
248    unlink $vsx_main_file;
249    unlink $vsx_sln_file;
250}
251
252sub main {
253    if( ! check_dirs() ) {
254        chdir '..' or die;
255        check_dirs or die "Must but run from mbedTLS root or scripts dir\n";
256    }
257
258    # Remove old files to ensure that, for example, project files from deleted
259    # apps are not kept
260    del_vsx_files();
261
262    my @app_list = get_app_list();
263    my @header_dirs = (
264                       $mbedtls_header_dir,
265                       $psa_header_dir,
266                       $test_header_dir,
267                       $test_drivers_header_dir,
268                       $source_dir,
269                       @thirdparty_header_dirs,
270                      );
271    my @headers = (map { <$_/*.h> } @header_dirs);
272    my @source_dirs = (
273                       $source_dir,
274                       $test_source_dir,
275                       @thirdparty_source_dirs,
276                      );
277    my @sources = (map { <$_/*.c> } @source_dirs);
278
279    @headers = grep { ! $excluded_files{$_} } @headers;
280    @sources = grep { ! $excluded_files{$_} } @sources;
281    map { s!/!\\!g } @headers;
282    map { s!/!\\!g } @sources;
283
284    gen_app_files( @app_list );
285
286    gen_main_file( \@headers, \@sources,
287                   $vsx_hdr_tpl, $vsx_src_tpl,
288                   $vsx_main_tpl_file, $vsx_main_file );
289
290    gen_vsx_solution( @app_list );
291
292    return 0;
293}
294