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