source: Jenkinsfile@ 959cc59

Last change on this file since 959cc59 was 8e5dc27, checked in by Peter A. Buhr <pabuhr@…>, 4 months ago

5th attempt at build on Ubuntu 24.04

  • Property mode set to 100644
File size: 13.3 KB
Line 
1#!groovy
2
3import groovy.transform.Field
4
5//===========================================================================================================
6// Main loop of the compilation
7//===========================================================================================================
8
9// Globals
10BuildDir = null
11SrcDir = null
12Settings = null
13Tools = null
14
15// Local variables
16def err = null
17def log_needed = false
18
19currentBuild.result = "SUCCESS"
20
21try {
22 node {
23 //Wrap build to add timestamp to command line
24 wrap([$class: 'TimestamperBuildWrapper']) {
25 Settings = prepare_build()
26 }
27 }
28
29 node(Settings.Architecture.node) {
30 //Wrap build to add timestamp to command line
31 wrap([$class: 'TimestamperBuildWrapper']) {
32 BuildDir = pwd tmp: true
33 SrcDir = pwd tmp: false
34 currentBuild.description = "${currentBuild.description} on ${env.NODE_NAME}"
35
36 Tools.Clean()
37
38 Tools.Checkout()
39
40 build()
41
42 test()
43
44 benchmark()
45
46 build_doc()
47
48 publish()
49 }
50 }
51}
52
53//If an exception is caught we need to change the status and remember to
54//attach the build log to the email
55catch (Exception caughtError) {
56 // Store the result of the build log
57 currentBuild.result = "FAILURE"
58
59 // An error has occured, the build log is relevent
60 log_needed = true
61
62 // rethrow error later
63 err = caughtError
64
65 // print the error so it shows in the log
66 echo err.toString()
67}
68
69finally {
70 //Send email with final results if this is not a full build
71 email(log_needed)
72
73 echo 'Build Completed'
74
75 /* Must re-throw exception to propagate error */
76 if (err) {
77 throw err
78 }
79}
80//===========================================================================================================
81// Main compilation routines
82//===========================================================================================================
83def build() {
84 debug = true
85 release = Settings.RunAllTests || Settings.RunBenchmark
86 Tools.BuildStage('Build : configure', true) {
87 // Configure must be run inside the tree
88 dir (SrcDir) {
89 // Generate the necessary build files
90 sh './autogen.sh'
91 }
92
93 // Build outside of the src tree to ease cleaning
94 dir (BuildDir) {
95 //Configure the compilation (Output is not relevant)
96 //Use the current directory as the installation target so nothing escapes the sandbox
97 //Also specify the compiler by hand
98 targets=""
99 if( Settings.RunAllTests || Settings.RunBenchmark ) {
100 targets="--with-target-hosts='host:debug,host:nodebug'"
101 } else {
102 targets="--with-target-hosts='host:debug'"
103 }
104
105 sh "${SrcDir}/configure CXX=${Settings.Compiler.CXX} CC=${Settings.Compiler.CC} ${Settings.Architecture.flags} AR=gcc-ar RANLIB=gcc-ranlib ${targets} --quiet --prefix=${BuildDir}"
106
107 // Configure libcfa
108 sh 'make -j $(nproc) --no-print-directory configure-libcfa'
109 }
110 }
111
112 Tools.BuildStage('Build : cfa-cpp', true) {
113 // Build outside of the src tree to ease cleaning
114 dir (BuildDir) {
115 // Build driver
116 sh 'make -j $(nproc) --no-print-directory -C driver'
117
118 // Build translator
119 sh 'make -j $(nproc) --no-print-directory -C src'
120 }
121 }
122
123 Tools.BuildStage('Build : libcfa(debug)', debug) {
124 // Build outside of the src tree to ease cleaning
125 dir (BuildDir) {
126 sh "make -j \$(nproc) --no-print-directory -C libcfa/${Settings.Architecture.name}-debug"
127 }
128 }
129
130 Tools.BuildStage('Build : libcfa(nodebug)', release) {
131 // Build outside of the src tree to ease cleaning
132 dir (BuildDir) {
133 sh "make -j \$(nproc) --no-print-directory -C libcfa/${Settings.Architecture.name}-nodebug"
134 }
135 }
136
137 Tools.BuildStage('Build : install', true) {
138 // Build outside of the src tree to ease cleaning
139 dir (BuildDir) {
140 sh 'make -j $(nproc) --no-print-directory install'
141 }
142 }
143}
144
145def test() {
146 try {
147 // Print potential limits before testing
148 // in case jenkins messes with them
149 sh 'free -h'
150 sh 'ulimit -a'
151
152 jopt = '-j $(nproc)'
153
154 Tools.BuildStage('Test: Debug', true) {
155 dir (BuildDir) {
156 //Run the tests from the tests directory
157 sh """make ${jopt} --no-print-directory -C tests timeout=600 global-timeout=14400 tests debug=yes archive-errors=${BuildDir}/tests/crashes/full-debug"""
158 }
159 }
160
161 Tools.BuildStage('Test: Release', Settings.RunAllTests) {
162 dir (BuildDir) {
163 //Run the tests from the tests directory
164 sh """make ${jopt} --no-print-directory -C tests timeout=600 global-timeout=14400 tests debug=no archive-errors=${BuildDir}/tests/crashes/full-nodebug"""
165 }
166 }
167 }
168 catch (Exception err) {
169 echo "Archiving core dumps"
170 dir (BuildDir) {
171 def exists = fileExists 'tests/crashes'
172 if( exists ) {
173 sh """${SrcDir}/tools/jenkins/archive-gen.sh"""
174 archiveArtifacts artifacts: "tests/crashes/**/*,lib/**/lib*.so*,setup.sh", fingerprint: true
175 }
176 }
177 throw err
178 }
179}
180
181def benchmark() {
182 Tools.BuildStage('Benchmark', Settings.RunBenchmark) {
183 dir (BuildDir) {
184 //Append bench results
185 sh "make --no-print-directory -C benchmark jenkins arch=${Settings.Architecture.name}"
186 }
187 }
188}
189
190def build_doc() {
191 Tools.BuildStage('Documentation', Settings.BuildDocumentation) {
192 dir ('doc/user') {
193 make_doc()
194 }
195
196 dir ('doc/refrat') {
197 make_doc()
198 }
199 }
200}
201
202def publish() {
203 Tools.BuildStage('Publish', true) {
204
205 if( Settings.Publish && !Settings.RunBenchmark ) { echo 'No results to publish!!!' }
206 }
207}
208
209//===========================================================================================================
210//Routine responsible of sending the email notification once the build is completed
211//===========================================================================================================
212//Standard build email notification
213def email(boolean log) {
214 node {
215 //Since tokenizer doesn't work, figure stuff out from the environnement variables and command line
216 //Configurations for email format
217 echo 'Notifying users of result'
218
219 def project_name = (env.JOB_NAME =~ /(.+)\/.+/)[0][1].toLowerCase()
220 def email_subject = "[${project_name} git][BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}] - branch ${env.BRANCH_NAME}"
221 def email_body = """<p>This is an automated email from the Jenkins build machine. It was
222generated because of a git hooks/post-receive script following
223a ref change which was pushed to the C\u2200 repository.</p>
224
225<p>- Status --------------------------------------------------------------</p>
226
227<p>BUILD# ${env.BUILD_NUMBER} - ${currentBuild.result}</p>
228<p>Check console output at ${env.BUILD_URL} to view the results.</p>
229""" + Tools.GitLogMessage()
230
231 def email_to = !Settings.IsSandbox ? "cforall@lists.uwaterloo.ca" : "tdelisle@uwaterloo.ca"
232
233 if( Settings && !Settings.Silent ) {
234 //send email notification
235 emailext body: email_body, subject: email_subject, to: email_to, attachLog: log
236 } else {
237 echo "Would send email to: ${email_to}"
238 echo "With title: ${email_subject}"
239 echo "Content: \n${email_body}"
240 }
241 }
242}
243
244//===========================================================================================================
245// Helper classes/variables/routines
246//===========================================================================================================
247//Description of a compiler (Must be serializable since pipelines are persistent)
248class CC_Desc implements Serializable {
249 public String name
250 public String CXX
251 public String CC
252 public String lto
253
254 CC_Desc(String name, String CXX, String CC, String lto) {
255 this.name = name
256 this.CXX = CXX
257 this.CC = CC
258 this.lto = lto
259 }
260}
261
262//Description of an architecture (Must be serializable since pipelines are persistent)
263class Arch_Desc implements Serializable {
264 public String name
265 public String flags
266 public String node
267
268 Arch_Desc(String name, String flags, String node) {
269 this.name = name
270 this.flags = flags
271 this.node = node
272 }
273}
274
275class BuildSettings implements Serializable {
276 public final CC_Desc Compiler
277 public final Arch_Desc Architecture
278 public final Boolean RunAllTests
279 public final Boolean RunBenchmark
280 public final Boolean BuildDocumentation
281 public final Boolean Publish
282 public final Boolean Silent
283 public final Boolean IsSandbox
284 public final String DescLong
285 public final String DescShort
286
287 public String GitNewRef
288 public String GitOldRef
289
290 BuildSettings(java.util.Collections$UnmodifiableMap param, String branch) {
291 switch( param.Compiler ) {
292 // builds runtime compiler cfa-cpp (clang missing -no-integrated-cpp)
293 // case 'gcc-4.9':
294 // this.Compiler = new CC_Desc('gcc-4.9', 'g++-4.9', 'gcc-4.9', '-flto=auto')
295 // break
296 // case 'gcc-5':
297 // this.Compiler = new CC_Desc('gcc-5', 'g++-5', 'gcc-5', '-flto=auto')
298 // break
299 // case 'gcc-6':
300 // this.Compiler = new CC_Desc('gcc-6', 'g++-6', 'gcc-6', '-flto=auto')
301 // break
302 // case 'gcc-7':
303 // this.Compiler = new CC_Desc('gcc-7', 'g++-7', 'gcc-7', '-flto=auto')
304 // break
305 // case 'gcc-8':
306 // this.Compiler = new CC_Desc('gcc-8', 'g++-8', 'gcc-8', '-flto=auto')
307 // break
308 case 'gcc-9':
309 this.Compiler = new CC_Desc('gcc-9', 'g++-9', 'gcc-9', '-flto=auto')
310 break
311 case 'gcc-10':
312 this.Compiler = new CC_Desc('gcc-10', 'g++-10', 'gcc-10', '-flto=auto')
313 break
314 case 'gcc-11':
315 this.Compiler = new CC_Desc('gcc-11', 'g++-11', 'gcc-11', '-flto=auto')
316 break
317 case 'gcc-12':
318 this.Compiler = new CC_Desc('gcc-12', 'g++-12', 'gcc-12', '-flto=auto')
319 break
320 // Use only generic clang/gcc here because of unknown version numbers on different architectures.
321 case 'clang':
322 this.Compiler = new CC_Desc('clang', 'clang++', 'gcc-11', '-flto=thin -flto-jobs=0')
323 break
324 default :
325 error "Unhandled compiler : ${cc}"
326 }
327
328 switch( param.Architecture ) {
329 case 'x64':
330 this.Architecture = new Arch_Desc('x64', '--host=x86_64', 'x64')
331 break
332 //case 'x86':
333 // this.Architecture = new Arch_Desc('x86', '--host=i386', 'x86')
334 //break
335 // case 'arm64':
336 // this.Architecture = new Arch_Desc('arm64', '--host=aarch64', 'arm64')
337 // break
338 default :
339 error "Unhandled architecture : ${arch}"
340 }
341
342 this.IsSandbox = (branch == "jenkins-sandbox")
343 this.RunAllTests = param.RunAllTests
344 this.RunBenchmark = param.RunBenchmark
345 this.BuildDocumentation = param.BuildDocumentation
346 this.Publish = param.Publish
347 this.Silent = param.Silent
348
349 def full = param.RunAllTests ? " (Full)" : ""
350 this.DescShort = "${ this.Compiler.name }:${ this.Architecture.name }${full}"
351
352 this.DescLong = """Compiler : ${ this.Compiler.name } (${ this.Compiler.CXX }/${ this.Compiler.CC })
353Architecture : ${ this.Architecture.name }
354Arc Flags : ${ this.Architecture.flags }
355Run All Tests : ${ this.RunAllTests.toString() }
356Run Benchmark : ${ this.RunBenchmark.toString() }
357Build Documentation : ${ this.BuildDocumentation.toString() }
358Publish : ${ this.Publish.toString() }
359Silent : ${ this.Silent.toString() }
360"""
361
362 this.GitNewRef = ''
363 this.GitOldRef = ''
364 }
365}
366
367def prepare_build() {
368 // prepare the properties
369 properties ([ \
370 buildDiscarder(logRotator( \
371 artifactDaysToKeepStr: '', \
372 artifactNumToKeepStr: '', \
373 daysToKeepStr: '730', \
374 numToKeepStr: '1000' \
375 )), \
376 [$class: 'ParametersDefinitionProperty', \
377 parameterDefinitions: [ \
378 [$class: 'ChoiceParameterDefinition', \
379 description: 'Which compiler to use', \
380 name: 'Compiler', \
381 choices: 'gcc-9\ngcc-10\ngcc-11\ngcc-12\ngcc-13\ngcc-14\nclang', \
382 defaultValue: 'gcc', \
383 ], \
384 [$class: 'ChoiceParameterDefinition', \
385 description: 'The target architecture', \
386 name: 'Architecture', \
387 choices: 'x64\nx86\narm64', \
388 defaultValue: 'x64', \
389 ], \
390 [$class: 'BooleanParameterDefinition', \
391 description: 'If false, the test suite is only ran in debug', \
392 name: 'RunAllTests', \
393 defaultValue: false, \
394 ], \
395 [$class: 'BooleanParameterDefinition', \
396 description: 'If true, jenkins also runs benchmarks', \
397 name: 'RunBenchmark', \
398 defaultValue: false, \
399 ], \
400 [$class: 'BooleanParameterDefinition', \
401 description: 'If true, jenkins also builds documentation', \
402 name: 'BuildDocumentation', \
403 defaultValue: true, \
404 ], \
405 [$class: 'BooleanParameterDefinition', \
406 description: 'If true, jenkins also publishes results', \
407 name: 'Publish', \
408 defaultValue: false, \
409 ], \
410 [$class: 'BooleanParameterDefinition', \
411 description: 'If true, jenkins will not send emails', \
412 name: 'Silent', \
413 defaultValue: false, \
414 ], \
415 ],
416 ]])
417 // choices: 'gcc-4.9\ngcc-5\ngcc-6\ngcc-7\ngcc-8\ngcc-9\ngcc-10\ngcc-11\nclang',
418 // defaultValue: 'gcc-8',
419
420 // It's unfortunate but it looks like we need to checkout the entire repo just to get
421 // - the pretty git printer
422 // - Jenkins.tools
423 checkout scm
424
425 Tools = load "Jenkins/tools.groovy"
426
427 final settings = new BuildSettings(params, env.BRANCH_NAME)
428
429 currentBuild.description = settings.DescShort
430 echo settings.DescLong
431
432 return settings
433}
434
435def make_doc() {
436 def err = null
437 try {
438 sh 'make clean > /dev/null'
439 sh 'make > /dev/null 2>&1'
440 }
441 catch (Exception caughtError) {
442 err = caughtError //rethrow error later
443 sh 'cat build/*.log'
444 }
445 finally {
446 if (err) throw err // Must re-throw exception to propagate error
447 }
448}
Note: See TracBrowser for help on using the repository browser.