Narzędzia do kompilacji#
Kompilowanie twojego projektu Fortran ręcznie może być dość skomplikowane w zależności od liczby plików źródłowych i współzależności w module. Obsługa różnych kompilatorów i programów łączących lub różnych platform może stawać się coraz bardziej skomplikowana dopóki nie zostaną użyte odpowiednie narzędzia do automatycznego wykonania tych zadań.
W zależności od rozmiaru twojego projektu i jego celu użyte mogą być różne narzędzia do automatyzacji kompilacji.
Na początek, twoje zintegrowane środowisko programistyczne prawdopodobnie zapewnia sposób na skompilowanie twojego programu. Popularnym międzyplatformowym narzędziem jest Microsoft Visual Studio Code, ale istnieją również inne, takie jak Atom, Eclipse Photran oraz Code::Blocks. Oferują one graficzny interfejs użytkownika, ale często są bardzo specyficzne dla kompilatora i platformy.
Dla mniejszych projektów powszechnym wyborem kompilacji programu jest system regułowy make
. Bazując na zdefiniowanych zasadach może wykonywać takie działania jak (re)kompilowanie plików obiektów z zaktualizowanych plików, tworzyć biblioteki oraz łączyć pliki wykonywalne. Aby użyć make
w twoim projekcie musisz zakodować te reguły w Makefile
, który definiuje współzależności finałowego programu, pośrednich obiektów oraz bibliotek i plików źródłowych. Krótkie wprowadzenie do tematu znajdziesz w przewodniku po make
.
Narzędzia konserwacyjne takie jak autotools i CMake mogą generować Makefiles lub pliki Visual Studio za pośrednictwem opisów wysokiego poziomu. Odbiegają one od specyfiki kompilatora i platformy.
To, na które z tych narzędzi będzie najlepsze dla twojego projektu zależy od wielu czynników. Wybierz narzędzie do kompilacji, z którym będzie ci się komfortowo pracować, nie powinno przeszkadzać ci podczas programowania. Poświęcanie większej ilości czasu na walkę z narzędziami do kompilacji niż na faktycznemu tworzeniu programu może szybko stać się frustrujące.
Zwróć również uwagę na dostępność twoich narzędzi do kompilacji. Jeśli są ograniczone do specyficznego zintegrowanego środowiska, czy wszyscy deweloperzy w twoim projekcie będą mieć dostęp do nich? Jeśli używasz konkretnego systemu kompilacji, czy działa on na wszystkich platformach, na które tworzysz program? Jak duża jest bariera wejścia twoich narzędzi do kompilacji? Rozważ również krzywą uczenia się dla narzędzi do kompilacji, idealne narzędzie do kompilacji będzie bezużyteczne jeśli najpierw musisz nauczyć się skomplikowanego języka programowania, aby dodać nowy plik źródłowy. Na koniec, zobacz czego używają inne projekty, takie, których używasz jako zależności i te które używają (lub będą używać) twojego projektu jako zależności.
Korzystanie z make jako narzędzia do kompilacji#
Najbardziej znanym i powszechnie używanym systemem kompilacji jest system make
. Wykonuje działania na podstawie zasad zdefiniowanych w pliku konfiguracyjnym nazywanym Makefile
lub makefile
, który zazwyczaj prowadzi do skompilowania programu z dostarczonego kodu źródłowego.
Wskazówka
Aby zobaczyć szczegółowy poradnik do make
odwiedź jego stronę informacyjną. Wersja online jego strony informacyjnej jest dostępna tutaj.
Zaczniemy od podstaw z początkowego folderu źródłowego. Utwórz i otwórz plik Makefile
, zaczniemy od prostej zasady all:
all:
echo "$@"
Po zapisaniu Makefile
otwórz go poprzez wykonanie make
w tym samym folderze. Powinieneś zobaczyć następujący wynik:
echo "all"
all
Po pierwsze zauważmy, że make
zastępuje nazwę reguły $@
. Po drugie, zauważmy, że make
zawsze drukuje polecenie, które wykonuje. Na koniec widzimy rezultat wykonania echo "all"
.
Informacja
Zgodnie z konwencją punkt wejścia naszego pliku Makefile
powinien nazywać się all, ale możesz wybrać dowolną nazwę.
Informacja
Jeśli twój edytor tekstu działa poprawnie to nie powinieneś tego zauważyć, ale musisz wciąć zawartość znaku reguły za pomocą tabulatora. W przypadku problemów z uruchomieniem pliku Makefile
możesz zobaczyć taki błąd
Makefile:2: *** missing separator. Stop.
Wcięcie jest prawdopodobnie niepoprawne. W tym przypadku zamień wcięcie w drugiej linii znakiem tabulacji.
Teraz chcemy stworzyć bardziej skomplikowane zasady, więc dodajemy kolejną regułę:
PROG := my_prog
all: $(PROG)
echo "$@ depends on $^"
$(PROG):
echo "$@"
Zauważmy jak deklarujemy zmienne w make
. Zmienne lokalne powinny być zawsze zadeklarowane poprzez :=
. Aby zdobyć dostęp do zawartości zmiennej używamy $(...)
, nazwa zmienniej musi być zawarta w nawiasach.
Informacja
Deklaracja zmiennych zazwyczaj odbywa się za pomocą :=
, jednak make
pozwala zarówno na zmienne =
, jak i na zmienne rekursywnie rozbudowane. Zwykle, pierwszy typ deklaracji jest bardziej pożądany, ponieważ jest bardziej przewidywalny i nie mają narzutu czasu wykonania wynikającego z rekurencyjnej rozbudowy.
Wprowadziliśmy zależność dla reguły all, a mianowicie zawartość zmiennej PROG
, zmodyfikowaliśmy również wydruk, a teraz chcemy zobaczyć wszystkie zależności tej reguły, które są przechowywane w zmiennej $^
. Teraz dla nowej reguły, której nadajemy nazwę po wartości zmiennej PROG
, która robi to samo, co zrobiliśmy wcześniej dla reguły all. Zwróćmy uwagę, jak wartość $@
jest zależna od reguły, w której jest używana.
Ponownie sprawdzamy poprzez wykonanie make
i powinniśmy zobaczyć:
echo "my_prog"
my_prog
echo "all depends on my_prog"
all depends on my_prog
Zależność została poprawnie rozwiązana i określona zanim jakakolwiek akcja na reguły all została wykonana. Teraz wykonajmy tylko drugą regułę: wpiszmy make my_prog
, a zobaczymy tylko dwa pierwsze wersy w terminalu.
Następnym krokiem jest wykonanie prawdziwych akcji z make
, weźmy kod źródłowy z poprzedniego rozdziału i dodajmy nowe reguły do naszego Makefile
:
OBJS := tabulate.o functions.o
PROG := my_prog
all: $(PROG)
$(PROG): $(OBJS)
gfortran -o $@ $^
$(OBJS): %.o: %.f90
gfortran -c -o $@ $<
Definiujemy OBJS
, które jest skrótem od object files (pliki obiektów). Nasz program zależy od OBJS
i dla każdego pliku obiektu tworzymy regułę, aby stworzyć je z pliku źródłowego. Ostatnia reguła, którą wprowadziliśmy to reguła dopasowania wzorca, %
jest wspólnym wzorcem dla tabulate.o
i tabulate.f90
, który łączy nasz plik obiektu tabulate.o
z plikiem źródłowym tabulate.f90
. Mając to ustawione, uruchamiamy nasz kompilator ( gfortran
) i tłumaczymy plik źródłowy na plik obiektu, nie tworzymy jeszcze pliku wykonywalnego z powodu flagi -c
. Zwróćmy uwagę na użycie $<
dla pierwszego elementu zależności tutaj.
Po skompilowaniu wszystkich plików obiektowych próbujemy połączyć program. Nie używamy bezpośredniego linkera, ale gfortran
do wygenerowania pliku wykonywalnego.
Teraz uruchamiamy skrypt kompilacji poleceniem make
:
gfortran -c -o tabulate.o tabulate.f90
tabulate.f90:2:7:
2 | use user_functions
| 1
Fatal Error: Cannot open module file ‘user_functions.mod’ for reading at (1): No such file or directory
compilation terminated.
make: *** [Makefile:10: tabulate.f90.o] Error 1
Pamiętamy, że mamy zależności pomiędzy naszymi plikami źródłowymi, dlatego dodajemy zależność jawnie do pliku Makefile
za pomocą
tabulate.o: functions.o
Teraz możemy ponowić próbę i zobaczyć, że kompilacja przebiegła pomyślnie. Rezultat powinien być następujący
gfortran -c -o functions.o functions.f90
gfortran -c -o tabulate.o tabulate.f90
gfortran -o my_prog tabulate.o functions.o
Powinieneś teraz znaleźć cztery nowe pliki w twoim folderze. Uruchom my_prog
, aby upewnić się, że wszystko działa zgodnie z oczekiwaniami. Teraz wykonajmy ponownie make
:
make: Nothing to be done for 'all'.
Korzystając z sygnatur czasowych pliku wykonywalnego make
udało się nam ustalić, że jest on nowszy niż tabulate.o
i functions.o
, które z kolei są nowsze niż tabulate.f90
i functions.f90
. Dlatego program jest już aktualny, zawiera najnowszy kod i nie trzeba wykonywać żadnych działań.
Na koniec, spójrzmy na kompletny plik Makefile
.
# Disable all of make's built-in rules (similar to Fortran's implicit none)
MAKEFLAGS += --no-builtin-rules --no-builtin-variables
# configuration
FC := gfortran
LD := $(FC)
RM := rm -f
# list of all source files
SRCS := tabulate.f90 functions.f90
PROG := my_prog
OBJS := $(addsuffix .o, $(SRCS))
.PHONY: all clean
all: $(PROG)
$(PROG): $(OBJS)
$(LD) -o $@ $^
$(OBJS): %.o: %
$(FC) -c -o $@ $<
# define dependencies between object files
tabulate.f90.o: functions.f90.o user_functions.mod
# rebuild all object files in case this Makefile changes
$(OBJS): $(MAKEFILE_LIST)
clean:
$(RM) $(filter %.o, $(OBJS)) $(wildcard *.mod) $(PROG)
Jako że zaczynasz od make
, zdecydowanie zalecamy, aby zawsze zawierać pierwszy wiersz, podobnie jak w przypadku implicit none
języka Fortran, nie chcemy, aby niejawne reguły zakłócały działanie naszego Makefile
w zaskakujący i szkodliwy sposób.
Następnie, mamy sekcję konfiguracji, gdzie definiujemy zmienne, w przypadku jeśli chcemy zmienić nasz kompilator może to być z łatwością zrobione tutaj. Wprowadzamy także zmienną SRCS
do przechowywania wszystkich plików źródłowych, co jest bardziej intuicyjne niż określanie plików obiektowych. Możemy z łatwością stworzyć plik obiektowy poprzez dodanie sufiksu .o
przy użyciu funkcji addsuffix
. .PHONY
jest specjalną regułą. która powinna być używana dla każdego punktu wejścia w Makefile
, tutaj definiujemy dwa punkty wejścia, all, już znamy, a nowa reguła clean usuwa ponownie wszystkie artefakty kompilacji, tak że zaczynamy od czystego folderu.
Ponadto, zmieniliśmy odrobinę regułę budowania dla plików obiektowych, aby uwzględnić dodanie sufiksu .o
zamiast go zastępować. Zwróćmy uwagę, że nadal musimy jawnie zadeklarować zależności w Makefile
. Dodaliśmy również zależność dla plików obiektowych w samym Makefile
, w przypadku zmiany kompilatora pozwoli to na bezpieczną rekompilację.
Teraz wiemy już wystarczająco o make
, aby używać go do kompilowania mniejszych projektów. Jeśli planujesz używać make
bardziej szczegółowo, zebraliśmy dla ciebie parę wskazówek.
Wskazówka
W tym poradniku pominęliśmy lub wyłączyliśmy wiele z powszechnie używanych funkcji make
, które mogą być szczególnie kłopotliwe jeśli zostaną użyte niewłaściwie. Zalecamy unikanie wbudowanych reguł i zmiennych, jeśli nie czujesz się pewnie pracując z make
, a jawne deklarowanie wszystkich zmiennych i reguł.
Przekonasz się, że make
jest dobrym narzędziem do zautomatyzowania krótkich współzależnych przepływów pracy i kompilowania mniejszych projektów. Jednak dla większych projektów, prawdopodobnie szybko zetkniesz się z jego ograniczeniami. Z tego powodu, make
nie jest używane samodzielnie, ale połączone z innymi narzędziami, aby wygenerować Makefile
w całości lub częściowo.
Zmienne rozszerzane rekurencyjnie#
Często w wielu projektach można zobaczyć zmienne rozszerzane rekurencyjnie (zadeklarowane za pomocą =
zamiast :=
). Rozszerzanie rekurencyjne zmiennych pozwala na deklarowanie poza kolejnością i inne sprytne sztuczki z make
, ponieważ są one zdefiniowane jako reguły, które są rozszerzane w czasie wykonania , a nie definiowane podczas przetwarzania.
Na przykład zadeklarowanie i użycie flag Fortranu za pomocą tego fragmentu kodu będzie działać całkowicie poprawnie:
all:
echo $(FFLAGS)
FFLAGS = $(include_dirs) -O
include_dirs += -I./include
include_dirs += -I/opt/some_dep/include
Powinieneś znaleźć oczekiwany (lub może nieoczekiwany) rezultat po wykonaniu make
echo -I./include -I/opt/some_dep/include -O
-I./include -I/opt/some_dep/include -O
Wskazówka
dołączenie +=
do niezdefiniowanej zmiennej stworzy zmienną rozszerzoną rekurencyjnie, a ten stan będzie dziedziczony przy każdym dalszym dołączeniu.
Podczas gdy może się wydawać to interesującą funkcją, czasem prowadzi do niespodziewanych i nieoczekiwanych rezultatów. Zwykle, podczas definiowania zmiennych jak twój kompilator, nie ma powodu, aby w ogóle używać rozszerzenia rekurencyjnego.
To samo może być z łatwością osiągnięte poprzez użycie deklaracji :=
:
all:
echo $(FFLAGS)
include_dirs := -I./include
include_dirs += -I/opt/some_dep/include
FFLAGS := $(include_dirs) -O
Ważne
zawsze myśl o Makefile
jako o całym zbiorze reguł, musi być przetworzony w całości zanim jakakolwiek zasada zostanie określona.
Możesz używać jakichkolwiek zmiennych, które lubisz, jednak powinieneś być ostrożny przy mieszaniu ich. Ważnym jest, aby być świadomym różnic pomiędzy tymi dwoma typami i ich konsekwencjami.
System kompilacji Meson#
Po tym jak nauczyliśmy się już podstaw make
, które nazywamy systemem kompilacji niskiego poziomu, teraz możemy zapoznać się z systemem kompilacji wysokiego poziomu jakim jest meson
. Podczas gdy w systemie niskiego poziomu musimy sprecyzować jak skompilować nasz program, w systemie wysokiego poziomu precyzujemy co skompilować. System wysokiego poziomu zajmie się sposobem i wygeneruje pliki kompilacji dla systemu kompilacji niskiego poziomu.
Istnieje wiele systemów kompilacji wysokiego poziomu, ale tutaj skupimy się na systemie meson
, ponieważ jest skonstruowany w sposób przyjazny dla użytkownika. Domyślny, niskopoziomowy system kompilacji meson
nazywa się ninja
.
Spójrzmy na kompletny plik meson.build
:
project('my_proj', 'fortran', meson_version: '>=0.49')
executable('my_prog', files('tabulate.f90', 'functions.f90'))
I już skończyliśmy, następnym krokiem jest skonfigurowanie naszego systemu kompilacji niskiego poziomu za pomocą meson setup build
, powinieneś zobaczyć dane wyjściowe nieco podobne do tego
The Meson build system
Version: 0.53.2
Source dir: /home/awvwgk/Examples
Build dir: /home/awvwgk/Examples/build
Build type: native build
Project name: my_proj
Project version: undefined
Fortran compiler for the host machine: gfortran (gcc 9.2.1 "GNU Fortran (Arch Linux 9.2.1+20200130-2) 9.2.1 20200130")
Fortran linker for the host machine: gfortran ld.bfd 2.34
Host machine cpu family: x86_64
Host machine cpu: x86_64
Build targets in project: 1
Found ninja-1.10.0 at /usr/bin/ninja
Informacje przedstawione tutaj są już w tym momencie dużo bardziej szczegółowe niż cokolwiek, co moglibyśmy zobaczyć w Makefile
, teraz rozpocznijmy kompilację przy pomocy ninja -C build
, która powinna pokazać coś takiego
[1/4] Compiling Fortran object 'my_prog@exe/functions.f90.o'.
[2/4] Dep hack
[3/4] Compiling Fortran object 'my_prog@exe/tabulate.f90.o'.
[4/4] Linking target my_prog.
Znajdź i przetestuj swój program w build/my_prog
, aby upewnić się, że działa prawidłowo. Możemy zauważyć, że kroki, które wykonał ninja
są takie same, jak te, które zakodowalibyśmy w Makefile
(w tym zależności), ale nie musieliśmy ich określać, spójrz ponownie na swój plik meson.build
:
project('my_proj', 'fortran', meson_version: '>=0.49')
executable('my_prog', files('tabulate.f90', 'functions.f90'))
Sprecyzowaliśmy tylko, że program jest projektem Fortran (który wymaga odpowiedniej wersji meson
) i kazaliśmy meson
zbudować plik wykonywalny my_prog
z plików tabulate.f90
i functions.f90
. Nie musieliśmy precyzować jak zbudować projekt, meson
zrobił to sam.
Informacja
meson
jest międzyplatformowym systemem kompilacji, projekt, który właśnie określiłeś dla swojego programu, może być użyty do kompilacji plików binarnych dla twojego natywnego systemu operacyjnego lub do cross-kompilacji twojego projektu dla innych platform. Podobnie, plik meson.build
jest przenośny i będzie działał również na różnych platformach.
Dokumentację systemu meson
można znaleźć na stronie internetowej kompilatora meson.
Tworzenie projektu CMake#
Podobnie jak meson
CMake jest również wysokopoziomowym systemem kompilacji, który jest powszechnie używany do kompilowania projektów w języku Fortran.
Informacja
CMake stosuję nieco inna strategię i zapewnia kompletny język programowania do tworzenia twoich plików kompilacji. Największą zaletą tego rozwiązania jest to, że możesz zrobić prawie wszystko za pomocą CMake, ale twoje pliki kompilacji CMake mogą stać się bardzo złożone tak samo jak program, który kompilujesz.
Rozpocznij przez stworzenie pliku CMakeLists.txt
z taką zawartością
cmake_minimum_required(VERSION 3.7)
project("my_proj" LANGUAGES "Fortran")
add_executable("my_prog" "tabulate.f90" "functions.f90")
Podobnie jak w systemie meson
już skończyliśmy z naszymi plikami kompilacji CMake. Konfigurujemy nasze niskopoziomowe pliki kompilacji przy pomocy cmake -B build -G Ninja
i powinniśmy zobaczyć rezultat podobny do tego
-- The Fortran compiler identification is GNU 10.2.0
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Check for working Fortran compiler: /usr/bin/f95 - skipped
-- Checking whether /usr/bin/f95 supports Fortran 90
-- Checking whether /usr/bin/f95 supports Fortran 90 - yes
-- Configuring done
-- Generating done
-- Build files have been written to: /home/awvwgk/Examples/build
Możesz być zaskoczony tym, że CMake próbuje używać kompilatora f95
, na szczęście jest to tylko symboliczny link do gfortran
w większości systemów, a nie rzeczywisty kompilator f95
. Aby dać CMake lepszą podpowiedź, możesz wyeksportować zmienną środowiskową FC=gfortran
, a po ponownym uruchomieniu powinien teraz pokazać poprawną nazwę kompilatora
-- The Fortran compiler identification is GNU 10.2.0
-- Detecting Fortran compiler ABI info
-- Detecting Fortran compiler ABI info - done
-- Check for working Fortran compiler: /usr/bin/gfortran - skipped
-- Checking whether /usr/bin/gfortran supports Fortran 90
-- Checking whether /usr/bin/gfortran supports Fortran 90 - yes
-- Configuring done
-- Generating done
-- Build files have been written to: /home/awvwgk/Example/build
W podobny sposób możesz użyć kompilatora Intel Fortran do skompilowania swojego projektu (ustaw FC=ifort
).
CMake wspiera kilka plików kompilacyjnych niskiego poziomu. Jako, że standardowy jest używany dla konkretnych platform, użyjemy po prostu ninja
, ponieważ już wcześniej użyliśmy go razem z meson
. Tak jak wcześniej, kompilujemy nasz program za pomocą ninja -C build
:
[1/6] Building Fortran preprocessed CMakeFiles/my_prog.dir/functions.f90-pp.f90
[2/6] Building Fortran preprocessed CMakeFiles/my_prog.dir/tabulate.f90-pp.f90
[3/6] Generating Fortran dyndep file CMakeFiles/my_prog.dir/Fortran.dd
[4/6] Building Fortran object CMakeFiles/my_prog.dir/functions.f90.o
[5/6] Building Fortran object CMakeFiles/my_prog.dir/tabulate.f90.o
[6/6] Linking Fortran executable my_prog
Znajdź i przetestuj swój program za pomocą build/my_prog
, aby upewnić się, że działa prawidłowo. Kroki, które wykonał ninja
są w pewnym sensie inne, ponieważ zazwyczaj istnieje więcej niż jeden sposób na napisanie plików kompilacyjnych niskiego poziomu, aby skompilować program. Na szczęście, nie musimy się tym martwić, ponieważ nas system kompilacji może zająć się tymi detalami za nas.
Na koniec szybko podsumujemy nasz skończony CMakeLists.txt
żeby sprecyzować nasz projekt:
cmake_minimum_required(VERSION 3.7)
project("my_proj" LANGUAGES "Fortran")
add_executable("my_prog" "tabulate.f90" "functions.f90")
Sprecyzowaliśmy już, że projekt jest projektem Fortran i powiedzieliśmy CMake, aby stworzył plik wykonywalny my_prog
z plików tabulate.f90
i functions.f90
. CMake sam wie jak skompilować plik wykonywalny ze wskazanych źródeł, dlatego nie musimy się martwić żadnymi właściwymi krokami procesu kompilacji.
Wskazówka
CMake’s official reference can be found at the
CMake webpage.
It is organised in manpages, which are also available with your local CMake
installation as well using man cmake
. While it covers all functionality of
CMake, it sometimes covers them only very briefly.
The SCons build system#
SCons is one another high-level cross-platform build system with automatic dependency analysis that supports Fortran projects. SCons configuration files are executed as Python scripts but it could be successfully used without knowledge about Python programming. The using of Python scripting if needed allows to handle build process and file naming in more sophisticated manner.
Informacja
SCons doesn’t automatically passes the external environment variables such as
PATH
therefore it will not find programs and tools that installed into
non-standard locations unless are specified or passed via appropriate variables.
That guaranties that build isn’t affected by external (especially user’s)
environment variables and build is repeatable. The most of such variables
and compiler options and flags are required to be configured within special
„isolated” Environments
(please refer to
User Guide
for additional information).
The SCons doesn’t use external low-level build systems and relies on own
build system. The ninja
support as external tool to generate ninja.build
file is highly experimental (available since scons 4.2) and required to be
enabled explicitly by additional configuration.
The simple SCons project is SConstruct
file that contains:
Program('my_proj', ['tabulate.f90', 'functions.f90'])
The next step is to build our project with command scons
:
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
gfortran -o functions.o -c functions.f90
gfortran -o tabulate.o -c tabulate.f90
gfortran -o my_proj tabulate.o functions.o
scons: done building targets.
or with scons -Q
to disable extended output:
gfortran -o functions.o -c functions.f90
gfortran -o tabulate.o -c tabulate.f90
gfortran -o my_proj tabulate.o functions.o
Find and test your program my_prog
at the same directory as source files
(by default) to ensure it works correctly.
To cleanup the build artifacts run scons -c
(or scons -Qc
):
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Cleaning targets ...
Removed functions.o
Removed user_functions.mod
Removed tabulate.o
Removed my_proj
scons: done cleaning targets.
In our SCons SConstruct
file
Program('my_proj', ['tabulate.f90', 'functions.f90'])
we specified executable target name my_proj
(optional, if omitted the first
source file name is used) and list of source files
['tabulate.f90', 'functions.f90']
. There is no need to specify project source
files language – it’s detected automatically by SCons for supported languages.
The list of source files could be specified with SCons Glob
function:
Program('my_proj', Glob('*.f90'))
or using SCons Split
function:
Program('my_proj', Split('tabulate.f90 functions.f90'))
or in more readable form by assigning variable:
src_files = Split('tabulate.f90 functions.f90')
Program('my_proj', src_files)
In case of Split
function the multiple lines could be used with Python
„triple-quote” syntax:
src_files = Split("""tabulate.f90
functions.f90""")
Program('my_proj', src_files)
Wskazówka
SCons official webpage provides: User Guide with extended description of various aspects how to handle the build process, Frequently Asked Questions page and man page.
Komentarze i znaki białe#
Istnieją pewne zastrzeżenia dotyczące znaków białych i komentarzy, które mogą się od czasu do czasu pojawiać podczas używania
make
. Po pierwsze,make
nie zna żadnego typu danych poza ciągami znaków, a domyślnym separatorem jest po prostu spacja. Oznacza to, żemake
będzie miał trudności ze zbudowaniem projektu, który ma spacje w nazwach plików. Jeśli napotkasz taki przypadek, zmiana nazwy pliku jest prawdopodobnie najłatwiejszym rozwiązaniem.Kolejnym powszechnym problemem są spacje na początku i na końcu. Po ich wprowadzeniu
make
bez problemu je zachowa, co ma znaczenie przy porównywaniu ciągów znaków wmake
.Można je wprowadzić przy pomocy komentarzy tak jak tutaj
Podczas gdy komentarz zostanie poprawnie usunięty przez
make
, dwie spacje na końcu są teraz częścią zawartości zmiennej. Wykonajmake
i sprawdź czy tak jest w rzeczywistości:Aby rozwiązać ten problem, możesz przesunąć komentarz lub usunąć spację za pomocą funkcji
strip
. Alternatywnym rozwiązaniem może być spróbowanie na złączenie ciągu znaków przy użyciujoin
.Koniec końców, żadne z tych rozwiązań nie sprawią, że twój
Makefile
będzie bardziej czytelny, dlatego rozsądnym jest, aby zwracać uwagę na znaki białe i komentarze podczas robienia i używaniamake
.