|
9 | 9 |
|
10 | 10 | addpath(plan.RootFolder) |
11 | 11 |
|
| 12 | +%% Self-test setup |
12 | 13 | if isMATLABReleaseOlderThan("R2023b") |
13 | 14 | plan("test") = matlab.buildtool.Task(Actions=@legacy_test); |
14 | 15 | elseif isMATLABReleaseOlderThan("R2024a") |
|
19 | 20 | plan("test") = matlab.buildtool.tasks.TestTask("test", Strict=false, TestResults="TestResults.xml"); |
20 | 21 | end |
21 | 22 |
|
| 23 | +td = plan.RootFolder + "/test"; |
| 24 | +srcs = [td+"/stdout_stderr_c.c", td+"/stdin_cpp.cpp", td+"/printenv.cpp", td+"/sleep.cpp"]; |
| 25 | +exes = [td+"/stdout_stderr_c.exe", td+"/stdin_cpp.exe", td+"/printenv.exe", td+"/sleep.exe"]; |
| 26 | +if ~isempty(get_compiler("fortran")) |
| 27 | + srcs = [srcs, td + "/stdout_stderr_fortran.f90", td + "/stdin_fortran.f90"]; |
| 28 | + exes = [exes, td+"/stdout_stderr_fortran.exe", td+"/stdin_fortran.exe"]; |
| 29 | +end |
| 30 | +plan("exe") = matlab.buildtool.Task(Inputs=srcs, Outputs=exes, Actions=@build_exe); |
| 31 | +plan("test").Dependencies = "exe"; |
| 32 | + |
22 | 33 | if ~isMATLABReleaseOlderThan("R2023b") |
23 | 34 | plan("clean") = matlab.buildtool.tasks.CleanTask; |
24 | 35 | end |
25 | 36 |
|
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 | | - |
31 | 37 | if ~isMATLABReleaseOlderThan("R2024a") |
32 | 38 | plan("check") = matlab.buildtool.tasks.CodeIssuesTask(pkg_name, IncludeSubfolders=true, ... |
33 | 39 | WarningThreshold=0, Results="CodeIssues.sarif"); |
34 | | - plan("coverage") = matlab.buildtool.tasks.TestTask(Description="code coverage", Dependencies="clean", SourceFiles="test", Strict=false, CodeCoverageResults="code-coverage.xml"); |
| 40 | + |
| 41 | + plan("coverage") = matlab.buildtool.tasks.TestTask(Description="code coverage", Dependencies="clean", SourceFiles="test", Strict=false, CodeCoverageResults="code-coverage.xml"); |
35 | 42 | end |
36 | 43 |
|
37 | 44 | %% MexTask |
|
51 | 58 | % name of MEX target function is name of first source file |
52 | 59 | if isMATLABReleaseOlderThan("R2024b") |
53 | 60 | 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()); |
| 61 | + plan(mex_name) = matlab.buildtool.Task(Inputs=src, Outputs=fullfile(bindir, name + "." + mexext()), ... |
| 62 | + Actions=@(context) legacy_mex(context, compiler_opt, linker_opt)); |
59 | 63 | mex_deps(end+1) = mex_name; %#ok<AGROW> |
60 | 64 | else |
61 | 65 | plan("mex:" + name) = matlab.buildtool.tasks.MexTask(src, bindir, ... |
@@ -96,112 +100,90 @@ function publishTask(context) |
96 | 100 | end |
97 | 101 |
|
98 | 102 |
|
99 | | -function subprocess_build_c(context) |
| 103 | +function build_exe(context) |
100 | 104 |
|
101 | | -td = context.Plan.RootFolder + "/test"; |
102 | | -src = td + "/stdout_stderr_c.c"; |
| 105 | +for i = 1:length(context.Task.Inputs) |
| 106 | + src = context.Task.Inputs(i); |
| 107 | + exe = context.Task.Outputs(i).paths; |
| 108 | + exe = exe(1); |
103 | 109 |
|
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 |
| 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) |
109 | 116 | end |
110 | 117 |
|
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 | + [comp, shell, outFlag] = get_build_cmd(lang); |
| 119 | + if isempty(comp), return, end |
| 120 | + |
| 121 | + cmd = join([comp, src.paths, outFlag + exe]); |
| 122 | + if ~isempty(shell) |
| 123 | + cmd = join([shell, "&&", cmd]); |
118 | 124 | end |
| 125 | + |
| 126 | + disp(cmd) |
| 127 | + system(cmd); |
119 | 128 | end |
120 | 129 |
|
121 | 130 | end |
122 | 131 |
|
123 | 132 |
|
124 | | -function subprocess_build_cpp(context) |
| 133 | +function [comp, shell] = get_compiler(lang) |
125 | 134 |
|
126 | | -td = context.Plan.RootFolder + "/test"; |
127 | | -src = [td + "/sleep.cpp", td + "/stdin_cpp.cpp"]; |
| 135 | +lang = lower(lang); |
128 | 136 |
|
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 |
| 137 | +co = mex.getCompilerConfigurations(lang); |
135 | 138 |
|
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) |
| 139 | +if isempty(co) |
| 140 | + switch lang |
| 141 | + case "fortran" |
| 142 | + comp = getenv("FC"); |
| 143 | + if isempty(comp) |
| 144 | + disp("set FC environment variable to the Fortran compiler path, or do 'mex -setup fortran'") |
| 145 | + end |
| 146 | + case "c++" |
| 147 | + comp = getenv("CXX"); |
| 148 | + if isempty(comp) |
| 149 | + disp("set CXX environment variable to the C++ compiler path, or do 'mex -setup c++") |
| 150 | + end |
| 151 | + case "c" |
| 152 | + comp = getenv("CC"); |
| 153 | + if isempty(comp) |
| 154 | + disp("set CC environment variable to the C compiler path, or do 'mex -setup c'") |
| 155 | + end |
| 156 | + otherwise, error("language not known " + lang) |
143 | 157 | end |
| 158 | +else |
| 159 | + comp = co.Details.CompilerExecutable; |
| 160 | + disp(lang + " compiler: " + co.ShortName + " " + co.Name + " " + co.Version + " " + comp) |
144 | 161 | end |
145 | 162 |
|
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 | 163 |
|
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 |
| 164 | +shell = string.empty; |
| 165 | +if ispc && ~isempty(co) |
| 166 | + disp("Shell: " + co.Details.CommandLineShell) |
160 | 167 |
|
161 | | - cmd = get_build_cmd("Fortran", s); |
162 | | - if isempty(cmd), return, end |
163 | | - cmd = cmd + exe; |
164 | | - disp(cmd) |
165 | | - [r, m] = system(cmd); |
166 | | - if r ~= 0 |
167 | | - disp("failed to build TestSubprocess " + exe + " " + m) |
| 168 | + if any(startsWith(co.ShortName, ["INTEL", "MSVC"])) |
| 169 | + shell = join([strcat('"',string(co.Details.CommandLineShell),'"'), ... |
| 170 | + co.Details.CommandLineShellArg], " "); |
168 | 171 | end |
169 | 172 | end |
170 | 173 |
|
171 | 174 | end |
172 | 175 |
|
173 | 176 |
|
174 | | -function cmd = get_build_cmd(lang, src) |
| 177 | +function [comp, shell, outFlag] = get_build_cmd(lang) |
175 | 178 |
|
176 | | -cmd = string.empty; |
| 179 | +outFlag = "-o"; |
177 | 180 |
|
178 | | -co = mex.getCompilerConfigurations(lang); |
179 | | -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 |
185 | | - end |
186 | | - disp(lang + " compiler not found") |
187 | | - return |
188 | | -else |
189 | | - comp = co.Details.CompilerExecutable; |
190 | | -end |
| 181 | +[comp, shell] = get_compiler(lang); |
191 | 182 |
|
192 | | -outFlag = "-o"; |
193 | | -shell = string.empty; |
194 | | -msvcLike = ispc && (contains(co.Name, "Visual Studio")); |
195 | | -if msvcLike |
196 | | - shell = join([strcat('"',string(co.Details.CommandLineShell),'"'), ... |
197 | | - co.Details.CommandLineShellArg], " "); |
| 183 | +if ~isempty(shell) |
198 | 184 | outFlag = "/Fo" + tempdir + " /link /out:"; |
199 | 185 | end |
200 | 186 |
|
201 | | -cmd = join([comp, src, outFlag]); |
202 | | -if ~isempty(shell) |
203 | | - cmd = join([shell, "&&", cmd]); |
204 | | -end |
205 | 187 |
|
206 | 188 | end |
207 | 189 |
|
|
0 commit comments