lint: Check that (cc-for-target) and friends are used.

"CC=gcc" is almost always incorrect; people often just don't
notice the incorrectness because they are compiling natively.
For an exception, see tzdata.

"guix style" partially made things worse, so I partially ignored it.

* guix/lint.scm (check-compiler-for-target): New linter.
* tests/lint.scm
("compiler-for-target: unconditional CC=gcc is unacceptable")
("compiler-for-target: looks through G-expressions")
("compiler-for-target: (cc-for-target) is acceptable")
("compiler-for-target: CC=gcc is acceptable when target=#false"):
Test it.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
Maxime Devos 2023-08-21 15:59:53 +02:00 committed by Ludovic Courtès
parent 05f44bbeb4
commit 96eda590e1
No known key found for this signature in database
GPG key ID: 090B11993D9AEBB5
2 changed files with 86 additions and 2 deletions

View file

@ -12,7 +12,7 @@
;;; Copyright © 2020 Chris Marusich <cmmarusich@gmail.com> ;;; Copyright © 2020 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com> ;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021, 2022 Maxime Devos <maximedevos@telenet.be> ;;; Copyright © 2021-2023 Maxime Devos <maximedevos@telenet.be>
;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re> ;;; Copyright © 2021 Brice Waegeneire <brice@waegenei.re>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
@ -114,6 +114,7 @@ (define-module (guix lint)
check-profile-collisions check-profile-collisions
check-haskell-stackage check-haskell-stackage
check-tests-true check-tests-true
check-compiler-for-target
lint-warning lint-warning
lint-warning? lint-warning?
@ -311,6 +312,55 @@ (define (tests-explicitly-enabled?)
#:field 'arguments)) #:field 'arguments))
'())) '()))
(define (check-compiler-for-target package)
"Check that cross-compilers are used when cross-compiling, by inspecting
#:make-flags."
(define (make-compiler-warning variable=value)
(define =-index (string-index variable=value #\=))
(define variable (substring variable=value 0 =-index))
(define value (substring variable=value (+ =-index 1)))
(make-warning package
(G_ "'~0@*~a' should be set to '~1@*~a' instead of '~2@*~a'")
(list variable
(match variable
("AR" "(ar-for-target)")
("AS" "(as-for-target)")
("CC" "(cc-for-target)")
("CXX" "(cxx-for-target)")
("LD" "(ld-for-target)")
("PKG_CONFIG" "(pkg-config-for-target)"))
value)
#:field 'arguments))
(define (find-incorrect-compilers l)
(match l
((or "AR=ar"
"AS=as"
;; 'cc' doesn't actually exist in Guix, but if it did,
;; it would be incorrect to use it w.r.t. cross-compilation.
"CC=cc" "CC=gcc" "CC=clang"
"CXX=g++"
"LD=ld"
"PKG_CONFIG=pkg-config")
(list (make-compiler-warning l)))
((x . y)
(append (find-incorrect-compilers x)
(find-incorrect-compilers y)))
(_ '())))
(parameterize ((%current-target-system "aarch64-linux-gnu"))
(apply (lambda* (#:key (target 'not-set)
make-flags #:allow-other-keys)
(define make-flags/sexp
(if (gexp? make-flags/sexp)
(gexp->approximate-sexp make-flags)
make-flags))
;; Some packages like 'tzdata' are never cross-compiled;
;; the compilers are only used to build tools for
;; compiling the rest of the package.
(if (eq? target '#false)
'()
(find-incorrect-compilers make-flags/sexp)))
(package-arguments package))))
(define (properly-starts-sentence? s) (define (properly-starts-sentence? s)
(string-match "^[(\"'`[:upper:][:digit:]]" s)) (string-match "^[(\"'`[:upper:][:digit:]]" s))
@ -1864,6 +1914,10 @@ (define %local-checkers
(name 'tests-true) (name 'tests-true)
(description "Check if tests are explicitly enabled") (description "Check if tests are explicitly enabled")
(check check-tests-true)) (check check-tests-true))
(lint-checker
(name 'compiler-for-target)
(description "Check that cross-compilers are used when cross-compiling")
(check check-compiler-for-target))
(lint-checker (lint-checker
(name 'description) (name 'description)
(description "Validate package descriptions") (description "Validate package descriptions")

View file

@ -10,7 +10,7 @@
;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com> ;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com>
;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr> ;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz> ;;; Copyright © 2021 Xinglu Chen <public@yoctocell.xyz>
;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be> ;;; Copyright © 2021, 2023 Maxime Devos <maximedevos@telenet.be>
;;; ;;;
;;; This file is part of GNU Guix. ;;; This file is part of GNU Guix.
;;; ;;;
@ -342,6 +342,36 @@ (define (warning-contains? str warnings)
`(#:tests? ,(not (%current-target-system))))))) `(#:tests? ,(not (%current-target-system)))))))
(check-tests-true pkg))) (check-tests-true pkg)))
(test-equal "compiler-for-target: unconditional CC=gcc is unacceptable"
"'CC' should be set to '(cc-for-target)' instead of 'gcc'"
(single-lint-warning-message
(check-compiler-for-target
(dummy-package "x" (arguments '(#:make-flags '("CC=gcc")))))))
(test-equal "compiler-for-target: looks through G-expressions"
"'CC' should be set to '(cc-for-target)' instead of 'gcc'"
(single-lint-warning-message
(check-compiler-for-target
(dummy-package "x" (arguments '(#:make-flags #~'("CC=gcc")))))))
(test-equal "compiler-for-target: (cc-for-target) is acceptable"
'()
(check-compiler-for-target
(dummy-package "x"
(arguments
(list #:make-flags
#~(list (string-append "CC=" (cc-for-target))))))))
(test-equal "compiler-for-target: CC=gcc is acceptable when target=#false"
'()
(check-compiler-for-target
;; This (dummy) package consists purely of architecture-independent data.
(dummy-package "tzdata"
(arguments
(list #:target #false
#:make-flags #~(list "CC=gcc"))))))
;; The emacs-build-system sets #:tests? #f by default. ;; The emacs-build-system sets #:tests? #f by default.
(test-equal "tests-true: #:tests? #t acceptable for emacs packages" (test-equal "tests-true: #:tests? #t acceptable for emacs packages"
'() '()