Skip to content

Commit 8c23b29

Browse files
committed
buildtool: functionalize, use incremental build
1 parent 39a77e8 commit 8c23b29

File tree

1 file changed

+64
-86
lines changed

1 file changed

+64
-86
lines changed

buildfile.m

Lines changed: 64 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,6 @@
2323
plan("clean") = matlab.buildtool.tasks.CleanTask;
2424
end
2525

26-
plan("build_c") = matlab.buildtool.Task(Actions=@subprocess_build_c);
27-
plan("build_cpp") = matlab.buildtool.Task(Actions=@subprocess_build_cpp);
28-
plan("build_fortran") = matlab.buildtool.Task(Actions=@subprocess_build_fortran);
29-
plan("test").Dependencies = ["build_c", "build_cpp", "build_fortran"];
30-
3126
if ~isMATLABReleaseOlderThan("R2024a")
3227
plan("check") = matlab.buildtool.tasks.CodeIssuesTask(pkg_name, IncludeSubfolders=true, ...
3328
WarningThreshold=0, Results="CodeIssues.sarif");
@@ -42,6 +37,19 @@
4237
% dummy task to allow "buildtool mex" to build all MEX targets
4338
plan("mex") = matlab.buildtool.Task();
4439
mex_deps = string.empty;
40+
else
41+
td = plan.RootFolder + "/test";
42+
43+
plan("exe:c") = matlab.buildtool.Task(Inputs=td+"/stdout_stderr_c.c", ...
44+
Outputs=td+"/stdout_stderr_c.exe", Actions=@build_exe);
45+
46+
plan("exe:cpp") = matlab.buildtool.Task(Inputs=td+"/stdin_cpp.cpp",...
47+
Outputs=td+"/stdin_cpp.exe", Actions=@build_exe);
48+
49+
plan("exe:fortran") = matlab.buildtool.Task(Inputs=[td + "/stdout_stderr_fortran.f90", td + "/stdin_fortran.f90"],...
50+
Outputs=[td+"/stdout_stderr_fortran.exe", td+"/stdin_fortran.exe"], Actions=@build_exe);
51+
52+
plan("test").Dependencies = "exe";
4553
end
4654

4755
for s = get_mex_sources()
@@ -51,11 +59,8 @@
5159
% name of MEX target function is name of first source file
5260
if isMATLABReleaseOlderThan("R2024b")
5361
mex_name = "mex_" + name;
54-
% specifying .Inputs and .Outputs enables incremental builds
55-
% https://www.mathworks.com/help/matlab/matlab_prog/improve-performance-with-incremental-builds.html
56-
plan(mex_name) = matlab.buildtool.Task(Actions=@(context) legacy_mex(context, compiler_opt, linker_opt));
57-
plan(mex_name).Inputs = src;
58-
plan(mex_name).Outputs = fullfile(bindir, name + "." + mexext());
62+
plan(mex_name) = matlab.buildtool.Task(Inputs=src, Outputs=fullfile(bindir, name + "." + mexext()), ...
63+
Actions=@(context) legacy_mex(context, compiler_opt, linker_opt));
5964
mex_deps(end+1) = mex_name; %#ok<AGROW>
6065
else
6166
plan("mex:" + name) = matlab.buildtool.tasks.MexTask(src, bindir, ...
@@ -96,71 +101,24 @@ function publishTask(context)
96101
end
97102

98103

99-
function subprocess_build_c(context)
100-
101-
td = context.Plan.RootFolder + "/test";
102-
src = td + "/stdout_stderr_c.c";
103-
104-
for s = src
105-
[~, n] = fileparts(s);
106-
exe = fullfile(td, n + ".exe");
107-
if stdlib.get_modtime(s) < stdlib.get_modtime(exe)
108-
continue
109-
end
110-
111-
cmd = get_build_cmd("c++", s);
112-
if isempty(cmd), return, end
113-
cmd = cmd + exe;
114-
disp(cmd)
115-
[r, m] = system(cmd);
116-
if r ~= 0
117-
disp("failed to build TestSubprocess " + exe + " " + m)
118-
end
119-
end
120-
121-
end
122-
123-
124-
function subprocess_build_cpp(context)
104+
function build_exe(context)
125105

126-
td = context.Plan.RootFolder + "/test";
127-
src = [td + "/sleep.cpp", td + "/stdin_cpp.cpp"];
128-
129-
for s = src
130-
[~, n] = fileparts(s);
131-
exe = fullfile(td, n + ".exe");
132-
if stdlib.get_modtime(s) < stdlib.get_modtime(exe)
133-
continue
134-
end
106+
for i = 1:length(context.Task.Inputs)
107+
src = context.Task.Inputs(i);
108+
exe = context.Task.Outputs(i);
135109

136-
cmd = get_build_cmd("c++", s);
137-
if isempty(cmd), return, end
138-
cmd = cmd + exe;
139-
disp(cmd)
140-
[r, m] = system(cmd);
141-
if r ~= 0
142-
disp("failed to build TestSubprocess " + exe + " " + m)
110+
[~,~,ext] = fileparts(src.paths);
111+
switch ext
112+
case ".c", lang = "c";
113+
case ".cpp", lang = "c++";
114+
case ".f90", lang = "fortran";
115+
otherwise, error("unknown code suffix " + ext)
143116
end
144-
end
145117

146-
end
147-
148-
149-
function subprocess_build_fortran(context)
150-
151-
td = context.Plan.RootFolder + "/test";
152-
src = [td + "/stdout_stderr_fortran.f90", td + "/stdin_fortran.f90"];
153-
154-
for s = src
155-
[~, n] = fileparts(s);
156-
exe = fullfile(td, n + ".exe");
157-
if stdlib.get_modtime(s) < stdlib.get_modtime(exe)
158-
continue
159-
end
118+
[comp, outFlag] = get_build_cmd(lang);
119+
if isempty(comp), return, end
160120

161-
cmd = get_build_cmd("Fortran", s);
162-
if isempty(cmd), return, end
163-
cmd = cmd + exe;
121+
cmd = join([comp, src.paths, outFlag + exe.paths]);
164122
disp(cmd)
165123
[r, m] = system(cmd);
166124
if r ~= 0
@@ -171,38 +129,58 @@ function subprocess_build_fortran(context)
171129
end
172130

173131

174-
function cmd = get_build_cmd(lang, src)
132+
function [comp, shell] = get_compiler(lang)
175133

176-
cmd = string.empty;
134+
lang = lower(lang);
177135

178136
co = mex.getCompilerConfigurations(lang);
137+
179138
if isempty(co)
180-
if lang == "Fortran"
181-
fc = getenv("FC");
182-
if isempty(fc)
183-
disp("set FC environment variable to the Fortran compiler executable, or do 'mex -setup fortran' to configure the Fortran compiler")
184-
end
139+
switch lang
140+
case "fortran"
141+
comp = getenv("FC");
142+
if isempty(comp)
143+
disp("set FC environment variable to the Fortran compiler path, or do 'mex -setup fortran'")
144+
end
145+
case "c++"
146+
comp = getenv("CXX");
147+
if isempty(comp)
148+
disp("set CXX environment variable to the C++ compiler path, or do 'mex -setup c++")
149+
end
150+
case "c"
151+
comp = getenv("CC");
152+
if isempty(comp)
153+
disp("set CC environment variable to the C compiler path, or do 'mex -setup c'")
154+
end
155+
otherwise, error("language not known " + lang)
185156
end
186-
disp(lang + " compiler not found")
187-
return
188157
else
189158
comp = co.Details.CompilerExecutable;
190159
end
191160

192-
outFlag = "-o";
193-
shell = string.empty;
194-
msvcLike = ispc && (contains(co.Name, "Visual Studio"));
195-
if msvcLike
161+
if ispc && contains(co.Name, "Visual Studio")
196162
shell = join([strcat('"',string(co.Details.CommandLineShell),'"'), ...
197163
co.Details.CommandLineShellArg], " ");
198-
outFlag = "/Fo" + tempdir + " /link /out:";
164+
else
165+
shell = string.empty;
199166
end
200167

201-
cmd = join([comp, src, outFlag]);
168+
end
169+
170+
171+
function [comp, outFlag] = get_build_cmd(lang)
172+
173+
outFlag = "-o";
174+
175+
[comp, shell] = get_compiler(lang);
176+
if isempty(comp), return, end
177+
202178
if ~isempty(shell)
203-
cmd = join([shell, "&&", cmd]);
179+
comp = join([shell, "&&", comp]);
204180
end
205181

182+
outFlag = "/Fo" + tempdir + " /link /out:";
183+
206184
end
207185

208186

0 commit comments

Comments
 (0)