1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21%%% Purpose : Autoconf for Windows.
22
23-module(ts_autoconf_win32).
24-export([configure/0]).
25
26-include("ts.hrl").
27
28configure() ->
29    case variables() of
30	{ok, Vars} ->
31	    ts_lib:subst_file("conf_vars.in", "conf_vars", Vars);
32	Error ->
33	    Error
34    end.
35
36variables() ->
37    run_tests(tests(), []).
38
39run_tests([{Prompt, Tester}|Rest], Vars) ->
40    io:format("checking ~s... ", [Prompt]),
41    case catch Tester(Vars) of
42	{'EXIT', Reason} ->
43	    io:format("FAILED~nExit status: ~p~n", [Reason]),
44	    {error, auto_conf_failed};
45	{Result, NewVars} ->
46	    io:format("~s~n", [lists:concat([Result])]),
47	    run_tests(Rest, NewVars)
48    end;
49run_tests([], Vars) ->
50    {ok, Vars}.
51
52%%% The tests.
53
54tests() ->
55    [{"host system type", fun system_type/1},
56     {"CPU type", fun cpu/1},
57     {"for C compiler", fun c_compiler/1},
58     {"for make program", fun make/1},
59     {"for location of SSL libraries", fun ssl/1},
60     {"for location of Java compiler", fun javac/1},
61     {"if wsl is to used as shell", fun wsl/1}
62    ].
63
64system_type(Vars) ->
65    Os = case os:type() of
66	     {win32, nt} ->
67		 case os:version() of
68		     {4,_,_} -> "Windows NT";
69		     {5,0,_} -> "Windows 2000";
70		     {5,1,_} -> "Windows XP";
71		     {5,2,_} -> "Windows 2003";
72		     {6,0,_} -> "Windows Vista";
73		     {6,1,_} -> "Windows 7";
74		     {_,_,_} -> "Windows NCC-1701-D"
75		 end;
76	     {win32, windows} ->
77		 case os:version() of
78		     {4,0,_} ->  "Windows 95";
79		     {4,10,_} -> "Windows 98"
80		 end;
81	     {win32, _} -> "Windows"
82	 end,
83    {Os, [{host_os, Os}, {host, "win32"}|Vars]}.
84
85cpu(Vars) ->
86    Arch = os:getenv("PROCESSOR_ARCHITECTURE"),
87    Level0 = os:getenv("PROCESSOR_Level"),
88    Cpu = case {Arch, Level0} of
89	      {"x86", Level} when is_list(Level) ->
90		  "i" ++ Level ++ "86";
91	      {Other, _Level} when is_list(Other) ->
92		  Other;
93	      {false, _} ->
94		  "i386"
95	  end,
96    {Cpu, [{host_cpu, Cpu}|Vars]}.
97
98c_compiler(Vars) ->
99    try
100	CompTests = [{msc, fun visual_cxx/1},
101		     {gnuc, fun mingw32/1}],
102	%% First try to find the same compiler that the system
103	%% was built with...
104	UsedCompiler = case erlang:system_info(c_compiler_used) of
105			   {UsedCmplr, _} ->
106			       case lists:keysearch(UsedCmplr, 1, CompTests) of
107				   {value, {UsedCmplr, CompTest}} ->
108				       CompTest(Vars);
109				   _ ->
110				       ok
111			       end,
112			       UsedCmplr;
113			   undefined ->
114			       undefined
115		       end,
116	%% ... then try to find a compiler...
117	lists:foreach(fun ({Cmplr, _CmplrTst}) when Cmplr =:= UsedCompiler ->
118			      ok; % Have already checked for this one
119			  ({_Cmplr, CmplrTst}) ->
120			      CmplrTst(Vars)
121		      end,
122		      CompTests),
123	{no, Vars}
124    catch
125	throw:{_Path, _NewVars} = Res -> Res
126    end.
127
128visual_cxx(Vars) ->
129    case os:find_executable("cl") of
130	false ->
131	    {no, Vars};
132	Path when is_list(Path) ->
133	    {DEFAULT_THR_LIB,
134	     ERTS_THR_LIB,
135	     DLL,
136	     DBG_LINK,
137	     DBG_COMP,
138	     OPT} =
139		case is_debug_build() of
140		    true ->
141			{"-MTd ",
142			 "-MDd ",
143			 "-LDd ",
144			 "-link -debug -pdb:none ",
145			 "-Z7 -DDEBUG",
146			 " "};
147		    false ->
148			{"-MT ",
149			 "-MD ",
150			 "-LD ",
151			 "-Zi -link ",
152			 "-Zi ",
153			 "-Ox "}
154		end,
155	    WIN32 = "-D__WIN32__ ",
156	    ERTS_CFLAGS = ERTS_THR_LIB ++ WIN32 ++ OPT ++ DBG_COMP,
157	    LIBS = "ws2_32.lib",
158	    CC = "cl -nologo",
159	    throw({Path, [{'CC', CC},
160			  {'LD', CC},
161			  {'SHLIB_LD', CC},
162			  {'SHLIB_LDFLAGS', ERTS_THR_LIB ++ DLL},
163			  {'SHLIB_LDLIBS', DBG_LINK ++ "kernel32.lib"},
164			  {'SHLIB_EXTRACT_ALL', ""},
165			  {'CFLAGS', DEFAULT_THR_LIB ++ WIN32 ++ DBG_COMP},
166			  {'EI_CFLAGS', DEFAULT_THR_LIB ++ WIN32 ++ DBG_COMP},
167			  {'ERTS_CFLAGS', ERTS_CFLAGS},
168			  {'SHLIB_CFLAGS', ERTS_CFLAGS++DLL},
169			  {'CROSSLDFLAGS', ""},
170			  {'DEFS', common_c_defs()},
171			  {'SHLIB_SUFFIX', ".dll"},
172			  {'ERTS_LIBS', ERTS_THR_LIB ++ LIBS},
173			  {'LIBS', DBG_LINK ++ LIBS},
174			  {obj,".obj"},
175			  {exe, ".exe"},
176			  {test_c_compiler, "{msc, undefined}"}
177			  | Vars]})
178    end.
179
180mingw32(Vars) ->
181    Gcc = "mingw32-gcc",
182    case os:find_executable(Gcc) of
183	false ->
184	    {no, Vars};
185	Path when is_list(Path) ->
186	    {DBG_COMP,
187	     OPT} =
188		case is_debug_build() of
189		    true ->
190			{"-DDEBUG",
191			 " "};
192		    false ->
193			{" ",
194			 "-O2 "}
195		end,
196	    WIN32 = "-D__WIN32__ ",
197	    ERTS_CFLAGS = WIN32 ++ "-g " ++ OPT ++ DBG_COMP,
198	    LIBS = "-lws2_32",
199	    CC = Gcc,
200	    throw({Path, [{'CC', CC},
201			  {'LD', CC},
202			  {'SHLIB_LD', CC},
203			  {'SHLIB_LDFLAGS', "-shared "},
204			  {'SHLIB_LDLIBS', " -lkernel32"},
205			  {'SHLIB_EXTRACT_ALL', ""},
206			  {'CFLAGS', WIN32 ++ DBG_COMP},
207			  {'EI_CFLAGS', WIN32 ++ DBG_COMP},
208			  {'ERTS_CFLAGS', ERTS_CFLAGS},
209			  {'SHLIB_CFLAGS', ERTS_CFLAGS},
210			  {'CROSSLDFLAGS', ""},
211			  {'DEFS', common_c_defs()},
212			  {'SHLIB_SUFFIX', ".dll"},
213			  {'ERTS_LIBS', LIBS},
214			  {'LIBS', LIBS},
215			  {obj,".o"},
216			  {exe, ".exe"},
217			  {test_c_compiler, "{gnuc, undefined}"}
218			  | Vars]})
219    end.
220
221common_c_defs() ->
222    "-DHAVE_STRERROR=1".
223
224make(Vars) ->
225    try
226	find_make("nmake -nologo", Vars),
227	find_make("mingw32-make", Vars)
228    catch
229	throw:{_Path, _NewVars} = Res -> Res
230    end.
231
232find_make(MakeCmd, Vars) ->
233    [Make|_] = string:lexemes(MakeCmd, " \t"),
234    case os:find_executable(Make) of
235	false ->
236	    {no, Vars};
237	Path when is_list(Path) ->
238	    throw({Path, [{make_command, MakeCmd} | Vars]})
239    end.
240
241ssl(Vars) ->
242    {"win32",[{'SSLEAY_ROOT',"win32"}|Vars]}.
243
244javac(Vars) ->
245    case os:find_executable("javac") of
246	false ->
247	    {no, Vars};
248	Path when is_list(Path) ->
249	    {Path, [{'JAVAC', "javac"} | Vars]}
250    end.
251
252wsl(Vars) ->
253    case os:getenv("WSLENV") of
254        false ->
255            {no, [{'wsl', ""} | Vars]};
256        _ ->
257            {"wsl.exe", [{'wsl', "wsl.exe"} | Vars]}
258    end.
259
260is_debug_build() ->
261    case catch string:find(erlang:system_info(system_version), "debug") of
262        nomatch ->
263            false;
264	_Else ->
265	    true
266    end.
267