Skip to content

Commit cfe1afd

Browse files
committed
buildfile: simplify, use private functions
buildfile was getting too big
1 parent 148da3a commit cfe1afd

File tree

5 files changed

+164
-160
lines changed

5 files changed

+164
-160
lines changed

buildfile.m

Lines changed: 9 additions & 160 deletions
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,15 @@
105105
if isMATLABReleaseOlderThan("R2024b"), return, end
106106

107107
%% MexTask
108-
[compiler_opt, linker_opt] = get_compiler_options();
109108

110109
for s = get_mex_sources()
111110
src = s{1};
112-
name = stdlib.stem(src(1));
111+
[~, name] = fileparts(src(1));
113112

114113
% name of MEX target function is name of first source file
115114
plan("mex:" + name) = matlab.buildtool.tasks.MexTask(src, pkg_root, ...
116115
Description="Build MEX target " + name, ...
117-
Options=[compiler_opt, linker_opt]);
116+
Options=get_compiler_options());
118117
end
119118

120119
end
@@ -151,118 +150,6 @@ function publishTask(context)
151150
end
152151

153152

154-
function build_exe(context)
155-
156-
for i = 1:length(context.Task.Inputs)
157-
src = context.Task.Inputs(i);
158-
exe = context.Task.Outputs(i).paths;
159-
exe = exe(1);
160-
161-
ext = stdlib.suffix(src.paths);
162-
switch ext
163-
case ".c", lang = "c";
164-
case ".cpp", lang = "c++";
165-
case ".f90", lang = "fortran";
166-
otherwise, error("unknown code suffix " + ext)
167-
end
168-
169-
[comp, shell, outFlag] = get_build_cmd(lang);
170-
if isempty(comp)
171-
return
172-
end
173-
if i == 1 && ~isempty(shell)
174-
disp("Shell: " + shell)
175-
end
176-
177-
cmd = join([comp, src.paths, outFlag + exe]);
178-
if ~isempty(shell)
179-
cmd = join([shell, "&&", cmd]);
180-
end
181-
182-
disp(cmd)
183-
[s, msg] = system(cmd);
184-
assert(s == 0, "Error %d: %s", s, msg)
185-
end
186-
187-
end
188-
189-
190-
function [comp, shell] = get_compiler(lang)
191-
arguments (Input)
192-
lang (1,1) string {mustBeMember(lang, ["c", "c++", "fortran"])}
193-
end
194-
arguments (Output)
195-
comp string {mustBeScalarOrEmpty}
196-
shell string {mustBeScalarOrEmpty}
197-
end
198-
199-
lang = lower(lang);
200-
201-
co = mex.getCompilerConfigurations(lang);
202-
203-
if isempty(co)
204-
switch lang
205-
case "fortran"
206-
comp = getenv("FC");
207-
if isempty(comp)
208-
comp = get_fortran_compiler();
209-
end
210-
case "c++"
211-
comp = getenv("CXX");
212-
if isempty(comp)
213-
disp("set CXX environment variable to the C++ compiler path, or do 'mex -setup c++")
214-
end
215-
case "c"
216-
comp = getenv("CC");
217-
if isempty(comp)
218-
disp("set CC environment variable to the C compiler path, or do 'mex -setup c'")
219-
end
220-
end
221-
else
222-
comp = co.Details.CompilerExecutable;
223-
% disp(lang + " compiler: " + co.ShortName + " " + co.Name + " " + co.Version + " " + comp)
224-
end
225-
226-
shell = string.empty;
227-
if ispc()
228-
if isempty(co)
229-
if any(contains(comp, ["gcc", "g++", "gfortran"]))
230-
shell = "set PATH=" + fileparts(comp) + pathsep + "%PATH%";
231-
end
232-
else
233-
if startsWith(co.ShortName, ["INTEL", "MSVC"])
234-
shell = join([strcat('"',string(co.Details.CommandLineShell),'"'), ...
235-
co.Details.CommandLineShellArg], " ");
236-
elseif startsWith(co.ShortName, "mingw64")
237-
shell = "set PATH=" + fileparts(comp) + pathsep + "%PATH%";
238-
end
239-
end
240-
end
241-
242-
end
243-
244-
245-
function [comp, shell, outFlag] = get_build_cmd(lang)
246-
arguments (Input)
247-
lang (1,1) string {mustBeMember(lang, ["c", "c++", "fortran"])}
248-
end
249-
arguments (Output)
250-
comp string {mustBeScalarOrEmpty}
251-
shell string {mustBeScalarOrEmpty}
252-
outFlag (1,1) string
253-
end
254-
255-
[comp, shell] = get_compiler(lang);
256-
257-
if any(contains(shell, "Visual Studio")) || endsWith(comp, "ifx.exe")
258-
outFlag = "/Fo" + tempdir + " /link /out:";
259-
else
260-
outFlag = "-o";
261-
end
262-
263-
end
264-
265-
266153
function srcs = get_mex_sources(build_all)
267154
arguments (Input)
268155
build_all (1,1) logical = false
@@ -287,21 +174,20 @@ function build_exe(context)
287174
end
288175

289176

290-
function [compiler_opt, linker_opt] = get_compiler_options()
177+
function opts = get_compiler_options()
291178
arguments (Output)
292-
compiler_opt (1,1) string
293-
linker_opt (1,1) string
179+
opts (1,1) string
294180
end
181+
% mex() can't handle string.empty
295182

296183
cxx = mex.getCompilerConfigurations('c++');
297184
flags = cxx.Details.CompilerFlags;
298185

299186
msvc = startsWith(cxx.ShortName, "MSVCPP");
300187

301188
std = "-std=c++17";
302-
% mex() can't handle string.empty
303-
linker_opt = "";
304189

190+
opts = "";
305191
if msvc
306192
std = "/std:c++17";
307193
% on Windows, Matlab doesn't register unsupported MSVC or oneAPI
@@ -311,52 +197,15 @@ function build_exe(context)
311197
end
312198

313199
if ~stdlib.version_atleast(cxx.Version, "9")
314-
linker_opt = "-lstdc++fs";
200+
opts = "-lstdc++fs";
315201
end
316202
end
317203

318204
opt = flags + " " + std;
319205
if msvc
320-
compiler_opt = "COMPFLAGS=" + opt;
206+
opts = opts + "COMPFLAGS=" + opt;
321207
else
322-
compiler_opt = "CXXFLAGS=" + opt;
208+
opts = opts + "CXXFLAGS=" + opt;
323209
end
324210

325211
end
326-
327-
328-
function comp = get_fortran_compiler()
329-
arguments (Output)
330-
comp string {mustBeScalarOrEmpty}
331-
end
332-
333-
if ismac()
334-
p = '/opt/homebrew/bin/';
335-
disp("on macOS, environment variables propagate in to GUI programs like Matlab by using 'launchctl setenv FC' and a reboot.")
336-
disp("if having trouble, try:")
337-
disp(" FC=gfortran matlab -batch 'buildtool exe'")
338-
elseif ispc()
339-
p = getenv('CMPLR_ROOT');
340-
if isempty(p)
341-
p = getenv("MW_MINGW64_LOC");
342-
end
343-
if ~endsWith(p, ["bin", "bin/"])
344-
p = p + "/bin";
345-
end
346-
else
347-
p = '';
348-
end
349-
350-
comp = string.empty;
351-
for fc = ["flang", "gfortran", "ifx"]
352-
comp = stdlib.which(fc, p);
353-
if ~isempty(comp)
354-
% disp(lang + " compiler: " + comp)
355-
setenv("FC", comp);
356-
return
357-
end
358-
end
359-
360-
disp("to hint Fortran compiler, setenv('FC', <Fortran compiler path>), or do 'mex -setup fortran'")
361-
362-
end

find_compiler.m

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
function comp = find_compiler(lang)
2+
arguments (Output)
3+
comp string {mustBeScalarOrEmpty}
4+
end
5+
6+
co = mex.getCompilerConfigurations(lang);
7+
8+
if ~isempty(co)
9+
comp = co.Details.CompilerExecutable;
10+
return
11+
end
12+
13+
if ismac()
14+
p = '/opt/homebrew/bin/';
15+
disp("on macOS, environment variables propagate in to GUI programs like Matlab by using 'launchctl setenv FC' and a reboot.")
16+
elseif ispc()
17+
p = getenv('CMPLR_ROOT');
18+
if isempty(p)
19+
p = getenv("MW_MINGW64_LOC");
20+
end
21+
if isempty(p)
22+
p = getenv("MINGWROOT");
23+
end
24+
if ~endsWith(p, ["bin", "bin/"])
25+
p = p + "/bin";
26+
end
27+
else
28+
p = '';
29+
end
30+
31+
comp = string.empty;
32+
33+
switch lang
34+
case "c", names = ["clang", "gcc", "icx"];
35+
case "c++", names = ["clang++", "g++", "icpx"];
36+
case "fortran", names = ["flang", "gfortran", "ifx"];
37+
otherwise, error('Unsupported language: %s', lang)
38+
end
39+
40+
for fc = names
41+
comp = stdlib.which(fc, p);
42+
if ~isempty(comp)
43+
return
44+
end
45+
end
46+
47+
end

private/build_exe.m

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
function build_exe(context)
2+
3+
for i = 1:length(context.Task.Inputs)
4+
src = context.Task.Inputs(i);
5+
exe = context.Task.Outputs(i).paths;
6+
exe = exe(1);
7+
8+
ext = stdlib.suffix(src.paths);
9+
switch ext
10+
case ".c", lang = "c";
11+
case ".cpp", lang = "c++";
12+
case ".f90", lang = "fortran";
13+
otherwise, error("unknown code suffix " + ext)
14+
end
15+
16+
[comp, shell, outFlag] = get_build_cmd(lang);
17+
if isempty(comp)
18+
return
19+
end
20+
if i == 1 && ~isempty(shell)
21+
disp("Shell: " + shell)
22+
end
23+
24+
cmd = join([comp, src.paths, outFlag + exe]);
25+
if ~isempty(shell)
26+
cmd = join([shell, "&&", cmd]);
27+
end
28+
29+
disp(cmd)
30+
[s, msg] = system(cmd);
31+
assert(s == 0, "Error %d: %s", s, msg)
32+
end
33+
34+
end

private/get_build_cmd.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
function [comp, shell, outFlag] = get_build_cmd(lang)
2+
arguments (Input)
3+
lang (1,1) string {mustBeMember(lang, ["c", "c++", "fortran"])}
4+
end
5+
arguments (Output)
6+
comp string {mustBeScalarOrEmpty}
7+
shell string {mustBeScalarOrEmpty}
8+
outFlag (1,1) string
9+
end
10+
11+
[comp, shell] = get_compiler(lang);
12+
13+
if any(contains(shell, "Visual Studio")) || endsWith(comp, "ifx.exe")
14+
outFlag = "/Fo" + tempdir + " /link /out:";
15+
else
16+
outFlag = "-o";
17+
end
18+
19+
end

private/get_compiler.m

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
function [comp, shell] = get_compiler(lang)
2+
arguments (Input)
3+
lang (1,1) string {mustBeMember(lang, ["c", "c++", "fortran"])}
4+
end
5+
arguments (Output)
6+
comp string {mustBeScalarOrEmpty}
7+
shell string {mustBeScalarOrEmpty}
8+
end
9+
10+
lang = lower(lang);
11+
12+
co = mex.getCompilerConfigurations(lang);
13+
14+
if isempty(co)
15+
switch lang
16+
case "fortran"
17+
comp = getenv("FC");
18+
if isempty(comp)
19+
disp("set FC environment variable to the Fortran compiler path via get_compiler('fortran'), or do 'mex -setup c++")
20+
end
21+
case "c++"
22+
comp = getenv("CXX");
23+
if isempty(comp)
24+
disp("set CXX environment variable to the C++ compiler path via get_compiler('c++'), or do 'mex -setup c++")
25+
end
26+
case "c"
27+
comp = getenv("CC");
28+
if isempty(comp)
29+
disp("set CC environment variable to the C compiler path via get_compiler('c'), or do 'mex -setup c'")
30+
end
31+
end
32+
else
33+
comp = co.Details.CompilerExecutable;
34+
% disp(lang + " compiler: " + co.ShortName + " " + co.Name + " " + co.Version + " " + comp)
35+
end
36+
37+
shell = string.empty;
38+
if ispc()
39+
if isempty(co)
40+
if any(contains(comp, ["gcc", "g++", "gfortran"]))
41+
shell = "set PATH=" + fileparts(comp) + pathsep + "%PATH%";
42+
end
43+
else
44+
if startsWith(co.ShortName, ["INTEL", "MSVC"])
45+
shell = join([strcat('"',string(co.Details.CommandLineShell),'"'), ...
46+
co.Details.CommandLineShellArg], " ");
47+
elseif startsWith(co.ShortName, "mingw64")
48+
shell = "set PATH=" + fileparts(comp) + pathsep + "%PATH%";
49+
end
50+
end
51+
end
52+
53+
end
54+
55+

0 commit comments

Comments
 (0)