piątek, 5 lutego 2021

GCC - Flagi kompilacji

W tym poście chciałbym opisać kilka rodzajów flag kompilatora GCC oraz parametry optymalizacji kodu.


   [Źródło: https://pl.wikipedia.org/wiki/GNU_Compiler_Collection]

Do testów można użyć program Compiler Explorer, gdzie w czasie rzeczywistym można podglądnąć zarówno wykonanie program jak i flagi kompilacji czy kod assemblera.

Poniżej opis niektórych flag wraz z przykładami zastosowania.

-Wall


Uruchomienie podstawowych flag generowania ostrzeżeń.

Wywołanie tej flagi uruchamia następujący zestaw flag:

  1. -Waddress
  2. -Warray-bounds=1 (only with -O2)
  3. -Warray-parameter=2 (C and Objective-C only)
  4. -Wbool-compare
  5. -Wbool-operation
  6. -Wc++11-compat -Wc++14-compat
  7. -Wcatch-value (C++ and Objective-C++ only)
  8. -Wchar-subscripts
  9. -Wcomment
  10. -Wduplicate-decl-specifier (C and Objective-C only)
  11. -Wenum-compare (in C/ObjC; this is on by default in C++)
  12. -Wformat
  13. -Wformat-overflow
  14. -Wformat-truncation
  15. -Wint-in-bool-context
  16. -Wimplicit (C and Objective-C only)
  17. -Wimplicit-int (C and Objective-C only)
  18. -Wimplicit-function-declaration (C and Objective-C only)
  19. -Winit-self (only for C++)
  20. -Wlogical-not-parentheses
  21. -Wmain (only for C/ObjC and unless -ffreestanding)
  22. -Wmaybe-uninitialized
  23. -Wmemset-elt-size
  24. -Wmemset-transposed-args
  25. -Wmisleading-indentation (only for C/C++)
  26. -Wmissing-attributes
  27. -Wmissing-braces (only for C/ObjC)
  28. -Wmultistatement-macros
  29. -Wnarrowing (only for C++)
  30. -Wnonnull
  31. -Wnonnull-compare
  32. -Wopenmp-simd
  33. -Wparentheses
  34. -Wpessimizing-move (only for C++)
  35. -Wpointer-sign
  36. -Wrange-loop-construct (only for C++)
  37. -Wreorder
  38. -Wrestrict
  39. -Wreturn-type
  40. -Wsequence-point
  41. -Wsign-compare (only in C++)
  42. -Wsizeof-array-div
  43. -Wsizeof-pointer-div
  44. -Wsizeof-pointer-memaccess
  45. -Wstrict-aliasing
  46. -Wstrict-overflow=1
  47. -Wswitch
  48. -Wtautological-compare
  49. -Wtrigraphs
  50. -Wuninitialized
  51. -Wunknown-pragmas
  52. -Wunused-function
  53. -Wunused-label
  54. -Wunused-value
  55. -Wunused-variable
  56. -Wvla-parameter (C and Objective-C only)
  57. -Wvolatile-register-var
  58. -Wzero-length-bounds

-Wextra


Uruchamia dodatkowe flagi ostrzeżeń.

Wykaz uruchamianych flag:

  1. -Wclobbered  
  2. -Wcast-function-type  
  3. -Wdeprecated-copy (C++ only)
  4. -Wempty-body  
  5. -Wenum-conversion (C only)
  6. -Wignored-qualifiers
  7. -Wimplicit-fallthrough=3
  8. -Wmissing-field-initializers  
  9. -Wmissing-parameter-type (C only)  
  10. -Wold-style-declaration (C only)  
  11. -Woverride-init  
  12. -Wsign-compare (C only)
  13. -Wstring-compare
  14. -Wredundant-move (only for C++)  
  15. -Wtype-limits  
  16. -Wuninitialized  
  17. -Wshift-negative-value (in C++03 and in C99 and newer)  
  18. -Wunused-parameter (only with -Wunused or -Wall)
  19. -Wunused-but-set-parameter (only with -Wunused or -Wall)

-Werror


Flaga pozwala na zmianę wszystkich ostrzeżeń w błędy.


Dzięki niej mamy pewność, że żadne ostrzeżenia nie dostaną się do finalnej wersji oprogramowania.

-Wfatal-errors


Zatrzymanie kompilacji na pierwszym napotkanym błędzie.

-Wshadow


Flaga nie została uwzględniona w -Wall ani w -Wextra. Kompilator wygeneruje ostrzeżenie o przysłonięciu zmiennej przez inną zmienną, która ma taką samą nazwę.


-Wdouble-promotion


Flaga nie została uwzględniona w -Wall ani w -Wextra.. Wygenerowanie ostrzeżenia gdy następuje promocja typu z float na double.


Jest to szczególne istotne w przypadku jednostek posiadających FPU. W przypadku promocji typu na double, obsługa typu nie jest już sprzętowa tylko programowa.

-Wundef


Wyświetlenie ostrzeżenie o występującej niezdefiniowanej wartości w deklaracji #if. Taka wartość zostanie zastąpiona przez wartość 0.


To ostrzeżenie pozwala na wyłapanie błędnie zdefiniowanej wartości w dyrektywie #if lub braku widoczności tej wartości w wykonywanym pliku.

-Wunused

Flaga uruchamia generowanie ostrzeżeń gdy w kodzie znajdują się elementy które nie są używane.
Jest ona uruchamiana automatycznie po wprowadzeniu flagi -Wall.

  1. -Wunused-function
  2. -Wunused-label
  3. -Wunused-value
  4. -Wunused-variable

oraz dla flagi -Wextra

  1. -Wunused-parameter (only with -Wunused or -Wall)
  2. -Wunused-but-set-parameter (only with -Wunused or -Wall)

-fno-common

Flaga pozwala na znalezienie dodatkowej definicji zmiennej globalnej, do której nie została przypisana wartość. 

Poniżej krótki przykład. Jeśli zapiszemy część programu w następujący sposób:

  1. uint8_t val1 = 4;
  2. uint8_t val1;
  3.  
  4. void setValue(uint8_t startValue) {
  5.   val1 = startValue;
  6. }
  7. int incrementValue(void) {
  8.   val1++;
  9. }
  10. int decrementValue(void) {
  11.   val1--;
  12. }

Program nie wygeneruje błędu i będzie można całość skompilować poprawnie. Oczywiście poważniejsze problemy pojawią się w przypadku wykorzystywania tych wartości do różnych operacji, gdzie nazwy mogą się dublować.

Kompilator nie zgłasza błędu ponieważ wartość nie została zainicjalizowana, a przez to pamięć dla niej nie została przydzielona.

Błąd podczas kompilacji nastąpi dopiero jak do drugiej zmiennej zostanie przydzielona wartość, lub gdy zmienne będą różnego typu. 

-g, -g3


Wyświetlanie dodatkowych informacji podczas debugowania aplikacji. 

-O0


Większość funkcji optymalizacyjnych została wyłączona. Jest to podstawowe ustawienie dla GCC.

-O1


Pozwala na wykonanie optymalizacji zarówno pod względem zmniejszenia czasu wykonywania jak i rozmiaru kodu

Można to bardzo łatwo zaobserwować na przykładzie redukcji ilości wykonywanych instrukcji assemblera np. za pomocą Compiler Explorer.

-O2


Zwiększenie optymalizacji pod względem szybkości wykonywania programu. Mniejsze rozwinięcie w stronę wielkości kodu.

-O3


Najwyższy poziom optymalizacji. 

-Os


Optymalizacji pod względem wielkości kodu. Uruchamia ona wszystkie flagi dla -O2 oraz kilka dodatkowych flag. Wyjątkiem są flagi, które powodują zwiększenia rozmiaru kodu.

  1. -falign-functions  
  2. -falign-jumps
  3. -falign-labels  
  4. -falign-loops
  5. -fprefetch-loop-arrays  
  6. -freorder-blocks-algorithm=stc
  7. -finline-functions

Zapewnia dosyć dobrą równowagę pomiędzy wielkością kodu a jego rozmiarem. Z tego powodu powinna być wykorzystywana w systemach wbudowanych.

-Ofast


Uruchamianie wszystkich flag dla -O3 oraz kilku dodatkowych flag.

-Og


Optymalizacja skierowana pod debugowanie oprogramowania. Zapewnia dobrze dobraną szybkość kompilacji do możliwości testowania programu.

Bibliografia:


https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
https://gcc.gnu.org/onlinedocs/gcc/Debugging-Options.html