aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bootstrap/src/Build.hs8
-rw-r--r--bootstrap/src/Fpm.hs198
-rw-r--r--fpm/src/fpm.f902
-rw-r--r--fpm/src/fpm_compiler.f902
-rw-r--r--fpm/src/fpm_source_parsing.f9035
-rw-r--r--fpm/src/fpm_sources.f9013
-rw-r--r--fpm/src/fpm_strings.f9025
-rw-r--r--fpm/test/fpm_test/test_source_parsing.f9061
-rw-r--r--manifest-reference.md6
9 files changed, 324 insertions, 26 deletions
diff --git a/bootstrap/src/Build.hs b/bootstrap/src/Build.hs
index 32d1979..724a1c6 100644
--- a/bootstrap/src/Build.hs
+++ b/bootstrap/src/Build.hs
@@ -75,7 +75,7 @@ buildProgram programDirectory' libraryDirectories sourceExtensions buildDirector
libraryModules <- findAvailableModules libraryDirectories
let programDirectory = foldl1 (</>) (splitDirectories programDirectory')
let buildDirectory = foldl1 (</>) (splitDirectories buildDirectory')
- let includeFlags = map (includeFlag ++) libraryDirectories
+ let includeFlags = (includeFlag ++ buildDirectory) : map (includeFlag ++) libraryDirectories
sourceFiles <- getDirectoriesFiles [programDirectory] sourceExtensions
rawSources <- mapM sourceFileToRawSource sourceFiles
let sources' = map processRawSource rawSources
@@ -108,7 +108,7 @@ buildProgram programDirectory' libraryDirectories sourceExtensions buildDirector
in fileMatcher &?> \(objectFile : _) -> do
need (sourceFile : directDependencies)
cmd compiler
- ["-c", moduleFlag ++ buildDirectory]
+ ["-c", moduleFlag, buildDirectory]
includeFlags
flags
["-o", objectFile, sourceFile]
@@ -130,7 +130,7 @@ buildLibrary
buildLibrary libraryDirectory sourceExtensions buildDirectory (CompilerSettings { compilerSettingsCompiler = compiler, compilerSettingsFlags = flags, compilerSettingsModuleFlag = moduleFlag, compilerSettingsIncludeFlag = includeFlag }) libraryName otherLibraryDirectories
= do
otherModules <- findAvailableModules otherLibraryDirectories
- let includeFlags = map (includeFlag ++) otherLibraryDirectories
+ let includeFlags = (includeFlag ++ buildDirectory) : map (includeFlag ++) otherLibraryDirectories
sourceFiles <- getDirectoriesFiles [libraryDirectory] sourceExtensions
rawSources <- mapM sourceFileToRawSource sourceFiles
let sources = map processRawSource rawSources
@@ -160,7 +160,7 @@ buildLibrary libraryDirectory sourceExtensions buildDirectory (CompilerSettings
in fileMatcher &?> \(objectFile : _) -> do
need (sourceFile : directDependencies)
cmd compiler
- ["-c", moduleFlag ++ buildDirectory]
+ ["-c", moduleFlag, buildDirectory]
includeFlags
flags
["-o", objectFile, sourceFile]
diff --git a/bootstrap/src/Fpm.hs b/bootstrap/src/Fpm.hs
index bec7706..10e14fe 100644
--- a/bootstrap/src/Fpm.hs
+++ b/bootstrap/src/Fpm.hs
@@ -71,6 +71,7 @@ import System.Exit ( ExitCode(..)
, exitWith
)
import System.Process ( readProcess
+ , readProcessWithExitCode
, system
)
import Toml ( TomlCodec
@@ -733,6 +734,185 @@ defineCompilerSettings specifiedFlags compiler release
, compilerSettingsModuleFlag = "-J"
, compilerSettingsIncludeFlag = "-I"
}
+ | "f95" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ [ "-O3"
+ , "-Wimplicit-interface"
+ , "-fPIC"
+ , "-fmax-errors=1"
+ , "-ffast-math"
+ , "-funroll-loops"
+ ]
+ else
+ [ "-Wall"
+ , "-Wextra"
+ , "-Wimplicit-interface"
+ , "-fPIC"
+ , "-fmax-errors=1"
+ , "-g"
+ , "-fbounds-check"
+ , "-fcheck-array-temporaries"
+ , "-Wno-maybe-uninitialized"
+ , "-Wno-uninitialized"
+ , "-fbacktrace"
+ ]
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-J"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "nvfortran" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ [ "-Mbackslash"
+ ]
+ else
+ [ "-Minform=inform"
+ , "-Mbackslash"
+ , "-g"
+ , "-Mbounds"
+ , "-Mchkptr"
+ , "-Mchkstk"
+ , "-traceback"
+ ]
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-module"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "ifort" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ [ "-fp-model", "precise"
+ , "-pc", "64"
+ , "-align", "all"
+ , "-error-limit", "1"
+ , "-reentrancy", "threaded"
+ , "-nogen-interfaces"
+ , "-assume", "byterecl"
+ , "-assume", "nounderscore"
+ ]
+ else
+ [ "-warn", "all"
+ , "-check:all:noarg_temp_created"
+ , "-error-limit", "1"
+ , "-O0"
+ , "-g"
+ , "-assume", "byterecl"
+ , "-traceback"
+ ]
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-module"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "ifx" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-module"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "pgfortran" `isInfixOf` compiler || "pgf90" `isInfixOf` compiler || "pgf95" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-module"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "flang" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-module"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "lfc" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-M"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "nagfor" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ [ "-O4"
+ , "-coarray=single"
+ , "-PIC"
+ ]
+ else
+ [ "-g"
+ , "-C=all"
+ , "-O0"
+ , "-gline"
+ , "-coarray=single"
+ , "-PIC"
+ ]
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-mdir"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "crayftn" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-J"
+ , compilerSettingsIncludeFlag = "-I"
+ }
+ | "xlf90" `isInfixOf` compiler
+ = let flags = case specifiedFlags of
+ [] -> if release
+ then
+ []
+ else
+ []
+ fs -> fs
+ in return $ CompilerSettings { compilerSettingsCompiler = compiler
+ , compilerSettingsFlags = flags
+ , compilerSettingsModuleFlag = "-qmoddir"
+ , compilerSettingsIncludeFlag = "-I"
+ }
| otherwise
= do
putStrLn $ "Sorry, compiler is currently unsupported: " ++ compiler
@@ -808,7 +988,23 @@ makeBuildPrefix :: FilePath -> [String] -> IO FilePath
makeBuildPrefix compiler flags = do
-- TODO Figure out what other info should be part of this
-- Probably version, and make sure to not include path to the compiler
- versionInfo <- readProcess compiler ["--version"] []
+ versionInfo <- do
+ (exitCode, stdout, stderr) <- readProcessWithExitCode compiler
+ ["--version"]
+ []
+ case exitCode of
+ ExitSuccess -> case stdout of
+ "" -> return stderr -- Guess this compiler outputs version info to stderr instead?
+ _ -> return stdout
+ _ -> do -- guess this compiler doesn't support the --version option. let's try -version
+ (exitCode, stdout, stderr) <- readProcessWithExitCode compiler
+ ["-version"]
+ []
+ case exitCode of
+ ExitSuccess -> case stdout of
+ "" -> return stderr -- Guess this compiler outputs version info to stderr instead?
+ _ -> return stdout
+ _ -> return "" -- Don't know how to get version info, we'll let defineCompilerSettings report it as unsupported
let compilerName = last (splitDirectories compiler)
let versionHash = abs (hash versionInfo)
let flagsHash = abs (hash flags)
diff --git a/fpm/src/fpm.f90 b/fpm/src/fpm.f90
index 79ced14..d91b1d4 100644
--- a/fpm/src/fpm.f90
+++ b/fpm/src/fpm.f90
@@ -1,5 +1,5 @@
module fpm
-use fpm_strings, only: string_t, str_ends_with, operator(.in.)
+use fpm_strings, only: string_t, operator(.in.)
use fpm_backend, only: build_package
use fpm_command_line, only: fpm_build_settings, fpm_new_settings, &
fpm_run_settings, fpm_install_settings, fpm_test_settings
diff --git a/fpm/src/fpm_compiler.f90 b/fpm/src/fpm_compiler.f90
index 6336e4e..0265985 100644
--- a/fpm/src/fpm_compiler.f90
+++ b/fpm/src/fpm_compiler.f90
@@ -141,7 +141,6 @@ character(len=:),allocatable :: mandatory ! flags required for fpm to function p
& -fp-model precise&
& -pc 64&
& -align all&
- & -coarray&
& -error-limit 1&
& -reentrancy threaded&
& -nogen-interfaces&
@@ -153,7 +152,6 @@ character(len=:),allocatable :: mandatory ! flags required for fpm to function p
fflags = '&
& -warn all&
& -check:all:noarg_temp_created&
- & -coarray&
& -error-limit 1&
& -O0&
& -g&
diff --git a/fpm/src/fpm_source_parsing.f90 b/fpm/src/fpm_source_parsing.f90
index ea5b4f9..f81555d 100644
--- a/fpm/src/fpm_source_parsing.f90
+++ b/fpm/src/fpm_source_parsing.f90
@@ -16,7 +16,7 @@
!>
module fpm_source_parsing
use fpm_error, only: error_t, file_parse_error, fatal_error
-use fpm_strings, only: string_t, split, lower, str_ends_with, fnv_1a
+use fpm_strings, only: string_t, string_cat, split, lower, str_ends_with, fnv_1a
use fpm_model, only: srcfile_t, &
FPM_UNIT_UNKNOWN, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, &
FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, &
@@ -86,6 +86,9 @@ function parse_f_source(f_filename,error) result(f_source)
file_lines = read_lines(fh)
close(fh)
+ ! Ignore empty files, returned as FPM_UNIT_UNKNOW
+ if (len_trim(string_cat(file_lines,' ')) < 1) return
+
f_source%digest = fnv_1a(file_lines)
do pass = 1,2
@@ -197,8 +200,14 @@ function parse_f_source(f_filename,error) result(f_source)
if (mod_name == 'procedure' .or. &
mod_name == 'subroutine' .or. &
- mod_name == 'function') then
- ! Ignore these cases
+ mod_name == 'function' .or. &
+ scan(mod_name,'=(')>0 ) then
+ ! Ignore these cases:
+ ! module procedure *
+ ! module function *
+ ! module subroutine *
+ ! module =*
+ ! module (i)
cycle
end if
@@ -275,7 +284,19 @@ function parse_f_source(f_filename,error) result(f_source)
! Detect if contains a program
! (no modules allowed after program def)
- if (index(adjustl(lower(file_lines(i)%s)),'program') == 1) then
+ if (index(adjustl(lower(file_lines(i)%s)),'program ') == 1) then
+
+ temp_string = lower(split_n(file_lines(i)%s,n=2,delims=' ',stat=stat))
+ if (stat == 0) then
+
+ if (scan(temp_string,'=(')>0 ) then
+ ! Ignore:
+ ! program =*
+ ! program (i) =*
+ cycle
+ end if
+
+ end if
f_source%unit_type = FPM_UNIT_PROGRAM
@@ -370,6 +391,12 @@ function parse_c_source(c_filename,error) result(c_source)
file_lines = read_lines(fh)
close(fh)
+ ! Ignore empty files, returned as FPM_UNIT_UNKNOW
+ if (len_trim(string_cat(file_lines,' ')) < 1) then
+ c_source%unit_type = FPM_UNIT_UNKNOWN
+ return
+ end if
+
c_source%digest = fnv_1a(file_lines)
do pass = 1,2
diff --git a/fpm/src/fpm_sources.f90 b/fpm/src/fpm_sources.f90
index de2df1c..3fffa81 100644
--- a/fpm/src/fpm_sources.f90
+++ b/fpm/src/fpm_sources.f90
@@ -15,6 +15,9 @@ implicit none
private
public :: add_sources_from_dir, add_executable_sources
+character(4), parameter :: fortran_suffixes(2) = [".f90", &
+ ".f "]
+
contains
!> Wrapper to source parsing routines.
@@ -24,7 +27,7 @@ function parse_source(source_file_path,error) result(source)
type(error_t), allocatable, intent(out) :: error
type(srcfile_t) :: source
- if (str_ends_with(lower(source_file_path), ".f90")) then
+ if (str_ends_with(lower(source_file_path), fortran_suffixes)) then
source = parse_f_source(source_file_path, error)
@@ -32,8 +35,7 @@ function parse_source(source_file_path,error) result(source)
source%exe_name = basename(source_file_path,suffix=.false.)
end if
- else if (str_ends_with(lower(source_file_path), ".c") .or. &
- str_ends_with(lower(source_file_path), ".h")) then
+ else if (str_ends_with(lower(source_file_path), [".c", ".h"])) then
source = parse_c_source(source_file_path,error)
@@ -80,9 +82,8 @@ subroutine add_sources_from_dir(sources,directory,scope,with_executables,recurse
end if
is_source = [(.not.(canon_path(file_names(i)%s) .in. existing_src_files) .and. &
- (str_ends_with(lower(file_names(i)%s), ".f90") .or. &
- str_ends_with(lower(file_names(i)%s), ".c") .or. &
- str_ends_with(lower(file_names(i)%s), ".h") ),i=1,size(file_names))]
+ (str_ends_with(lower(file_names(i)%s), fortran_suffixes) .or. &
+ str_ends_with(lower(file_names(i)%s),[".c",".h"]) ),i=1,size(file_names))]
src_file_names = pack(file_names,is_source)
allocate(dir_sources(size(src_file_names)))
diff --git a/fpm/src/fpm_strings.f90 b/fpm/src/fpm_strings.f90
index ea1db01..8e57d5b 100644
--- a/fpm/src/fpm_strings.f90
+++ b/fpm/src/fpm_strings.f90
@@ -24,9 +24,14 @@ interface fnv_1a
procedure :: fnv_1a_string_t
end interface fnv_1a
+interface str_ends_with
+ procedure :: str_ends_with_str
+ procedure :: str_ends_with_any
+end interface str_ends_with
+
contains
-logical function str_ends_with(s, e) result(r)
+pure logical function str_ends_with_str(s, e) result(r)
character(*), intent(in) :: s, e
integer :: n1, n2
n1 = len(s)-len(e)+1
@@ -36,7 +41,23 @@ logical function str_ends_with(s, e) result(r)
else
r = (s(n1:n2) == e)
end if
-end function str_ends_with
+end function str_ends_with_str
+
+pure logical function str_ends_with_any(s, e) result(r)
+ character(*), intent(in) :: s
+ character(*), intent(in) :: e(:)
+
+ integer :: i
+
+ r = .true.
+ do i=1,size(e)
+
+ if (str_ends_with(s,trim(e(i)))) return
+
+ end do
+ r = .false.
+
+end function str_ends_with_any
function f_string(c_string)
use iso_c_binding
diff --git a/fpm/test/fpm_test/test_source_parsing.f90 b/fpm/test/fpm_test/test_source_parsing.f90
index 4463c07..79a4d7a 100644
--- a/fpm/test/fpm_test/test_source_parsing.f90
+++ b/fpm/test/fpm_test/test_source_parsing.f90
@@ -24,6 +24,7 @@ contains
& new_unittest("modules-used", test_modules_used), &
& new_unittest("intrinsic-modules-used", test_intrinsic_modules_used), &
& new_unittest("include-stmt", test_include_stmt), &
+ & new_unittest("program", test_program), &
& new_unittest("module", test_module), &
& new_unittest("program-with-module", test_program_with_module), &
& new_unittest("submodule", test_submodule), &
@@ -238,6 +239,61 @@ contains
end subroutine test_include_stmt
+ !> Try to parse a simple fortran program
+ subroutine test_program(error)
+
+ !> Error handling
+ type(error_t), allocatable, intent(out) :: error
+
+ integer :: unit
+ character(:), allocatable :: temp_file
+ type(srcfile_t), allocatable :: f_source
+
+ allocate(temp_file, source=get_temp_filename())
+
+ open(file=temp_file, newunit=unit)
+ write(unit, '(a)') &
+ & 'program my_program', &
+ & 'use module_one', &
+ & 'implicit none', &
+ & 'integer :: module', &
+ & 'module = 1', &
+ & 'module= 1', &
+ & 'module =1', &
+ & 'module (i) =1', &
+ & 'contains', &
+ & 'subroutine f()', &
+ & 'end subroutine f', &
+ & 'end program my_program'
+ close(unit)
+
+ f_source = parse_f_source(temp_file,error)
+ if (allocated(error)) then
+ return
+ end if
+
+ if (f_source%unit_type /= FPM_UNIT_PROGRAM) then
+ call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM')
+ return
+ end if
+
+ if (size(f_source%modules_provided) /= 0) then
+ call test_failed(error,'Unexpected modules_provided - expecting zero')
+ return
+ end if
+
+ if (size(f_source%modules_used) /= 1) then
+ call test_failed(error,'Incorrect number of modules_used - expecting one')
+ return
+ end if
+
+ if (.not.('module_one' .in. f_source%modules_used)) then
+ call test_failed(error,'Missing module in modules_used')
+ return
+ end if
+
+ end subroutine test_program
+
!> Try to parse fortran module
subroutine test_module(error)
@@ -258,6 +314,11 @@ contains
& 'interface', &
& ' module subroutine f()', &
& 'end interface', &
+ & 'integer :: program', &
+ & 'program = 1', &
+ & 'program= 1', &
+ & 'program =1', &
+ & 'program (i) =1', &
& 'contains', &
& 'module procedure f()', &
& 'end procedure f', &
diff --git a/manifest-reference.md b/manifest-reference.md
index 07235b9..8e9f65d 100644
--- a/manifest-reference.md
+++ b/manifest-reference.md
@@ -233,8 +233,6 @@ The source file containing the program body can be specified in the *main* entry
Executables can have their own dependencies.
See [specifying dependencies](#specifying-dependencies) for more details.
-> Dependencies supported in Bootstrap fpm only
-
Executables can also specify their own external library dependencies.
See [external libraries](#link-external-libraries) for more details.
@@ -277,8 +275,6 @@ The source file containing the program body can be specified in the *main* entry
Examples can have their own dependencies.
See [specifying dependencies](#specifying-dependencies) for more details.
-> Dependencies supported in Bootstrap fpm only
-
Examples can also specify their own external library dependencies.
See [external libraries](#link-external-libraries) for more details.
@@ -313,8 +309,6 @@ The source file containing the program body can be specified in the *main* entry
Tests can have their own dependencies.
See [specifying dependencies](#specifying-dependencies) for more details.
-> Dependencies supported in Bootstrap fpm only
-
Tests can also specify their own external library dependencies.
See [external libraries](#link-external-libraries) for more details.