~ruther/guix-local

96eda590e1eb288359532d92bbfc4795c60f3df5 — Maxime Devos 2 years ago 05f44bb
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>
2 files changed, 86 insertions(+), 2 deletions(-)

M guix/lint.scm
M tests/lint.scm
M guix/lint.scm => guix/lint.scm +55 -1
@@ 12,7 12,7 @@
;;; Copyright © 2020 Chris Marusich <cmmarusich@gmail.com>
;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com>
;;; 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>
;;;
;;; This file is part of GNU Guix.


@@ 114,6 114,7 @@
            check-profile-collisions
            check-haskell-stackage
            check-tests-true
            check-compiler-for-target

            lint-warning
            lint-warning?


@@ 311,6 312,55 @@ superfluous when building natively and incorrect when cross-compiling."
                          #: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)
  (string-match "^[(\"'`[:upper:][:digit:]]" s))



@@ 1865,6 1915,10 @@ them for PACKAGE."
     (description "Check if tests are explicitly enabled")
     (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
     (name        'description)
     (description "Validate package descriptions")
     (check       check-description-style))

M tests/lint.scm => tests/lint.scm +31 -1
@@ 10,7 10,7 @@
;;; Copyright © 2020 Timothy Sample <samplet@ngyro.com>
;;; Copyright © 2020 Tobias Geerinckx-Rice <me@tobias.gr>
;;; 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.
;;;


@@ 342,6 342,36 @@
                             `(#:tests? ,(not (%current-target-system)))))))
    (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.
(test-equal "tests-true: #:tests? #t acceptable for emacs packages"
  '()