에러 및 경고 옵션

에러 및 경고 옵션

컴파일할 때 에러와 경고를 어떻게 다룰지 정해주는 옵션들을 살펴볼게요. 에러는 코드가 컴파일되지 못하게 막지만, 경고는 컴파일은 되게 하면서도 코드에 문제가 있을 만한 부분을 미리 알려주는 역할을 해요. 이 옵션들을 잘 조합하면 코드 품질을 한 단계 올리기 좋아요.

출처: Options to Request or Suppress Errors and Warnings (The GNU Fortran Compiler)

본문

에러는 GNU Fortran 컴파일러가 해당 소스 코드를 컴파일할 수 없다고 알려주는 진단 메시지예요. 컴파일러는 디버깅을 돕기 위해 추가 에러를 계속 보고하려고 프로그램을 계속 처리하지만, 컴파일된 출력물은 만들지 않아요.

경고는 본질적으로 오류는 아니지만 위험하거나 프로그램에 버그가 있을 가능성을 시사하는 구조에 대해 알려주는 진단 메시지예요. -Werror를 지정하지 않는 한 경고는 프로그램 컴파일을 막지 않아요.

-W로 시작하는 옵션으로 여러 구체적인 경고를 요청할 수 있어요. 예를 들어 -Wimplicit은 암시적 선언에 대한 경고를 요청하고, 이 옵션들은 각각 -Wno-로 시작하는 부정형을 써서 경고를 끌 수도 있어요. 예를 들면 -Wno-implicit처럼요. 이 매뉴얼은 기본값이 아닌 쪽, 두 형태 중 한 가지만 나열해요.

이 옵션들은 GNU Fortran이 만들어내는 에러와 경고의 양과 종류를 제어해요:

  • -fmax-errors=n: 에러 메시지의 최대 개수를 n으로 제한해요. 그 개수에 도달하면 GNU Fortran은 소스 코드를 계속 처리하려 하지 않고 중단해요. n이 0이면 에러 메시지 수에 제한이 없어요.

  • -fsyntax-only: 코드에 문법 에러가 있는지만 검사하고 실제로는 컴파일하지 않아요. 코드에 있는 각 모듈에 대한 모듈 파일은 생성하지만, 그 외 출력 파일은 만들지 않아요.

  • -Wpedantic / -pedantic: Fortran 확장 사용에 대한 경고를 내보내요. -pedantic#include 같은 지시문 안의 문자 상수에서 '\e'를 쓰는 것처럼, GNU Fortran 소스 파일에 나타나는 C 언어 구조에도 적용돼요. 올바른 Fortran 프로그램은 이 옵션을 켜든 끄든 컴파일돼야 해요. 다만 옵션이 없으면 일부 GNU 확장과 전통적인 Fortran 기능도 지원되고, 옵션을 켜면 그중 상당수가 거부돼요. 어떤 사용자는 이 옵션으로 프로그램의 표준 준수를 검사하려 하지만, 생각만큼 완벽하진 않아요 — 표준에 어긋나는 일부를 찾지만 전부 찾아주는 건 아니죠. 그래도 이 분야에 대한 GNU Fortran의 개선은 언제나 환영이에요. 이 옵션은 -std=f95, -std=f2003, -std=f2008, -std=f2018 또는 -std=f2023과 함께 쓰는 걸 권장해요.

  • -pedantic-errors: -pedantic과 같지만, 경고 대신 에러를 만들어내요.

  • -Wall: 피하는 걸 권장하고 쉽게 피할 수 있다고 판단되는 사용 방식에 대한, 흔히 쓰이는 경고 옵션들을 켜요. 현재 여기에는 -Waliasing, -Wampersand, -Wconversion, -Wsurprising, -Wc-binding-type, -Wintrinsics-std, -Wtabs, -Wintrinsic-shadow, -Wline-truncation, -Wtarget-lifetime, -Winteger-division, -Wreal-q-constant, -Wunused, -Wundefined-do-loop, -Wundefined-vars가 포함돼요.

  • -Waliasing: 가짜 인자(dummy argument)의 가능한 앨리어싱에 대해 경고해요. 구체적으로는 명시적 인터페이스가 있는 호출에서 같은 실제 인자가 INTENT(IN) 가짜 인자와 INTENT(OUT) 가짜 인자에 모두 연결될 때 경고해요. 다음 예제가 이 경고를 발생시켜요:

      interface
        subroutine bar(a,b)
          integer, intent(in) :: a
          integer, intent(out) :: b
        end subroutine
      end interface
      integer :: a
    
      call bar(a,a)
    
  • -Wampersand: 계속되는(continued) 문자 상수에서 빠진 앰퍼샌드에 대해 경고해요. 이 경고는 -Wampersand, -pedantic, -std=f95, -std=f2003, -std=f2008, -std=f2018, -std=f2023과 함께 제공돼요. 참고: 계속되는 문자 상수에 앰퍼샌드가 없으면 GNU Fortran은 이어짐을 시작한 앰퍼샌드 뒤의 첫 번째 주석이 아닌, 공백이 아닌 문자에서 계속된다고 가정해요.

  • -Warray-temporaries: 컴파일러가 만든 배열 임시 변수(temporary)에 대해 경고해요. 이 경고가 만드는 정보는 최적화에서 이런 임시 변수를 피하는 데 가끔 유용해요.

  • -Wc-binding-type: 변수가 C와 상호운용(interoperable)되지 않을 수도 있을 때 경고해요. 특히 내장 ISO_C_Binding 모듈에서 C 상호운용용으로 정의된 kind 매개변수 대신 기본 kind의 내장 타입으로 변수를 선언했을 때 경고해요. 이 옵션은 -Wall에 포함돼요.

  • -Wcharacter-truncation: 문자 할당이 할당된 문자열을 잘라낼 때 경고해요.

  • -Wline-truncation: 소스 코드 줄이 잘릴 때 경고해요. 이 옵션은 -Wall에 포함돼요. 자유 형식(free-form) 소스 코드에서는 기본값이 -Werror=line-truncation이라 잘림이 에러로 보고돼요.

  • -Wconversion: 변환 후 표현식의 값을 바꿀 가능성이 큰 암시적 변환에 대해 경고해요. -Wall에 포함돼요.

  • -Wconversion-extra: 서로 다른 타입과 kind 사이의 암시적 변환에 대해 경고해요. 이 옵션은 -Wconversion을 포함하지 않아요.

  • -Wdeprecated-openmp: 더 이상 쓰지 않는(deprecated) OpenMP 코드 사용에 대해 경고해요.

  • -Wexternal-argument-mismatch: 외부 프로시저의 가짜 인자 불일치에 대해 경고해요. 그런 경우에는 올바른 C23 인터페이스를 생성할 수 없기 때문에 -fc-prototypes-external에 포함돼요. -Wall에도 포함돼요.

  • -Wextra: 문제가 될 수 있는 언어 기능 사용에 대한 몇몇 경고 옵션을 켜요. 현재 여기에는 -Wcompare-reals, -Wunused-parameter, -Wdo-subscript, -Wunused-intent-out, -Wunused-read가 포함돼요.

  • -Wfrontend-loop-interchange: -ffrontend-loop-interchange를 사용해 루프 교환(loop interchange)을 수행할 때 경고해요.

  • -Wimplicit-interface: 프로시저를 명시적 인터페이스 없이 호출할 때 경고해요. 이건 명시적 인터페이스가 있는지만 확인해요. 선언된 인터페이스가 프로그램 단위들 사이에서 일관적인지는 검사하지 않아요.

  • -Wimplicit-procedure: 명시적 인터페이스도 없고 EXTERNAL로도 선언되지 않은 프로시저를 호출할 때 경고해요.

  • -Winteger-division: 상수 정수 나눗셈이 결과를 잘라낼 때 경고해요. 예를 들어 3/50으로 계산돼요.

  • -Wintrinsics-std: gfortran이 현재 선택된 표준(-std)에서 쓸 수 없는 내장 함수(intrinsic)와 같은 이름의 프로시저를 찾아서, 그 때문에 EXTERNAL 프로시저로 취급할 때 경고해요. -fall-intrinsics를 쓰면 이 동작이 절대 촉발되지 않고 선택된 표준과 무관하게 항상 내장 함수에 연결해요.

  • -Wno-overwrite-recursive: -fno-automatic-frecursive와 함께 쓸 때 경고하지 않아요. 관련 로컬 변수에 AUTOMATIC 속성이 명시적으로 선언돼 있지 않으면 재귀가 깨져요. 이 옵션은 재귀가 깨지지 않는 걸 알 때 경고를 억제하는 데 써요. -Werror를 쓰는 빌드 환경에서 유용해요.

  • -Wreal-q-constant: 실수-리터럴-상수(real-literal-constant)에 q 지수 문자(exponent-letter)가 포함되면 경고를 내보내요.

  • -Wsurprising: '수상한' 코드 구조를 만났을 때 경고를 내보내요. 기술적으로는 합법이어도 보통 실수가 있었음을 나타내는 경우죠. 현재 다음 상황에서 경고를 만들어요:

    • INTEGERSELECT CASE 구조에서 하한 값이 상한 값보다 커서 절대 매칭될 수 없는 CASE가 있는 경우.
    • LOGICALSELECT CASE 구조에 CASE 문이 세 개 있는 경우.
    • TRANSFER가 대상보다 짧은 원본(source)을 지정하는 경우.
    • 함수 결과 타입이 같은 타입으로 두 번 이상 선언된 경우. (-pedantic 또는 표준 준수 모드가 켜져 있으면 이건 에러예요.)
    • CHARACTER 변수가 음수 길이로 선언된 경우.
    • -fopenmp와 함께, 고정 형식(fixed-form) 소스 코드에서 omx 공급업체 확장 센티널(sentinel)이 쓰인 경우. (자유 형식 소스 코드에서 쓰이는 동등한 ompx는 기본적으로 진단돼요.)
    • -fopenacc와 함께, 변수를 받는 절(clause)에 이름 있는 상수를 사용해도 효과가 없는 경우.
  • -Wtabs: 기본적으로 탭은 공백으로 받아들여지지만, 탭은 Fortran 문자 집합의 구성원이 아니에요. 이어지는 줄을 위해 1에서 9 사이의 숫자가 뒤에 오는 탭은 지원돼요. -Wtabs는 탭을 만나면 경고를 내보내요. 참고: -Wtabs-pedantic, -std=f95, -std=f2003, -std=f2008, -std=f2018, -std=f2023, -Wall에서 활성화돼요.

  • -Wundefined-do-loop: 보폭(step)이 1 또는 -1인 DO 루프가 루프의 유도 변수(induction variable) 반복 중에 언더플로우나 오버플로우를 낼 때 경고해요. 이 옵션은 -Wall에 포함돼요.

  • -Wundefined-vars: 정의될 수 없는(값이 할당된 적 없는) 변수가 사용되는 걸 발견하면 경고해요. 여기에는 할당되지 않은 allocatable 변수 사용도 포함돼요.

  • -Wunderflow: 컴파일 중에 언더플로우를 내는 수치 상수 표현식을 만날 때 경고를 내보내요. 기본적으로 켜져 있어요.

  • -Wintrinsic-shadow: 사용자 정의 프로시저나 모듈 프로시저가 내장 함수와 같은 이름일 때 경고해요. 이 경우 나중에 호출이 원하는 내장 함수/프로시저로 해석되도록 명시적 인터페이스나 EXTERNAL/INTRINSIC 선언이 필요할 수 있어요. 이 옵션은 -Wall에 포함돼요.

  • -Wuse-without-only: USE 문에 ONLY 한정자가 없어서 사용한 모듈의 모든 공개 엔티티를 암시적으로 가져올 때 경고해요.

  • -Wunused-dummy-argument: 사용되지 않는 가짜 인자에 대해 경고해요. 이 옵션은 -Wall에 포함돼요.

  • -Wunused-parameter: gcc의 -Wunused-parameter 의미와 달리, gfortran의 이 옵션은 사용되지 않는 가짜 인자(-Wunused-dummy-argument 참고)가 아니라 사용되지 않는 PARAMETER 값에 대해 경고해요. -Wunused-parameter-Wunused-Wall도 사용되면 -Wextra에 포함돼요.

  • -Wunused-intent-out: INTENT(OUT) 인자로 전달된 뒤 그 값을 사용하지 않는 변수에 대해 경고해요. 이 옵션은 -Wextra에 포함돼요. 다음 코드가 이 경고가 발생하는 예시예요:

    module y
      implicit none
    contains
      subroutine bar
        real :: a
        call foo(a) ! Warning will be emitted here
      end subroutine bar
      subroutine foo(x)
        real, intent(out) :: x
        x = 0.4
      end subroutine foo
    end module y
    
  • -Wunused-read: READ 문에서 값이 결코 사용되지 않는 변수에 대해 경고해요. 이 경고는 -Wextra에 포함돼요. 다음 코드가 이 경고가 발생하는 예시예요:

    program main
      real :: x
      read (*,*) x
    end program main
    
  • -Walign-commons: 기본적으로 gfortran은 COMMON 블록 안에서 변수가 올바른 정렬을 위해 패딩되는 모든 경우에 대해 경고해요. 이 경고는 -Wno-align-commons로 끌 수 있어요. -falign-commons도 참고하세요.

  • -Wfunction-elimination: -ffrontend-optimize 옵션이 켜는 최적화로 불순(impure) 함수에 대한 호출이 제거되면 경고해요. 이 옵션은 -Wextra에 포함돼요.

  • -Wrealloc-lhs: 컴파일러가 내장 타입의 allocatable 배열 변수를 내장 할당에서 할당/재할당하는 코드를 넣을 수도 있을 때 경고해요. 바쁜 루프에서는 Fortran 2003의 재할당 기능이 성능을 떨어뜨릴 수 있어요. 배열이 이미 올바른 형태로 할당돼 있다면, 재할당 검사를 막기 위해 왼쪽 변수에 전체-배열 배열-지정(array-spec)(예: (:,:,:))을 사용하는 걸 고려해보세요. 어떤 경우에는 컴파일러가 재할당 검사를 최적화로 없애도 경고가 표시될 수 있어요. 예를 들어 오른쪽에 같은 변수를 스칼라로 곱하는 경우가 그렇죠. -frealloc-lhs도 참고하세요.

  • -Wrealloc-lhs-all: 컴파일러가 allocatable 변수(스칼라와 파생 타입 포함)를 할당/재할당하는 코드를 넣을 때 경고해요.

  • -Wcompare-reals: 실수나 복소수 타입을 같음/다름으로 비교할 때 경고해요. 이 옵션은 -Wextra에 포함돼요.

  • -Wtarget-lifetime: 포인터 할당에서 포인터가 대상(target)보다 더 오래 살 수도 있을 때 경고해요. 이 옵션은 -Wall에 포함돼요.

  • -Wzerotrip: DO 루프가 컴파일 타임에 0번 실행되는 걸 알 때 경고해요. 이 옵션은 -Wall에 포함돼요.

  • -Wdo-subscript: 다음처럼 컴파일러가 문장이 실제로 실행되는지 증명할 수 없어도 DO 루프 안의 배열 첨자가 경계를 벗어난 접근으로 이어질 수 있을 때 경고해요:

      real a(3)
      do i=1,4
        if (condition(i)) then
          a(i) = 1.2
        end if
      end do
    

    이 옵션은 -Wextra에 포함돼요.

  • -Werror: 모든 경고를 에러로 바꿔요.

더 알아보기