Skip to content

Create specification for example section #280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 67 additions & 6 deletions bootstrap/src/Fpm.hs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ data Arguments =
}
| Run
{ runRelease :: Bool
, runExample :: Bool
, runCompiler :: FilePath
, runFlags :: [String]
, runRunner :: Maybe String
Expand All @@ -111,6 +112,7 @@ data TomlSettings = TomlSettings {
tomlSettingsProjectName :: String
, tomlSettingsLibrary :: (Maybe Library)
, tomlSettingsExecutables :: [Executable]
, tomlSettingsExamples :: [Executable]
, tomlSettingsTests :: [Executable]
, tomlSettingsDependencies :: (Map.Map String Version)
, tomlSettingsDevDependencies :: (Map.Map String Version)
Expand All @@ -122,6 +124,7 @@ data AppSettings = AppSettings {
, appSettingsBuildPrefix :: String
, appSettingsLibrary :: (Maybe Library)
, appSettingsExecutables :: [Executable]
, appSettingsExamples :: [Executable]
, appSettingsTests :: [Executable]
, appSettingsDependencies :: (Map.Map String Version)
, appSettingsDevDependencies :: (Map.Map String Version)
Expand Down Expand Up @@ -168,15 +171,23 @@ start args = case args of
app :: Arguments -> AppSettings -> IO ()
app args settings = case args of
Build{} -> build settings
Run { runTarget = whichOne, runArgs = runArgs, runRunner = runner } -> do
Run { runTarget = whichOne, runArgs = runArgs, runRunner = runner, runExample = runExample } -> do
build settings
let buildPrefix = appSettingsBuildPrefix settings
let
executableNames = map
(\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } ->
sourceDir </> name
)
(appSettingsExecutables settings)
executableNames = if runExample
then
map
(\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } ->
sourceDir </> name
)
(appSettingsExamples settings)
else
map
(\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } ->
sourceDir </> name
)
(appSettingsExecutables settings)
let executables =
map (buildPrefix </>) $ map (flip (<.>) exe) executableNames
canonicalExecutables <- mapM makeAbsolute executables
Expand Down Expand Up @@ -265,6 +276,7 @@ build settings = do
let projectName = appSettingsProjectName settings
let buildPrefix = appSettingsBuildPrefix settings
let executables = appSettingsExecutables settings
let examples = appSettingsExamples settings
let tests = appSettingsTests settings
mainDependencyTrees <- fetchDependencies (appSettingsDependencies settings)
builtDependencies <- buildDependencies buildPrefix
Expand Down Expand Up @@ -319,6 +331,29 @@ build settings = do
devDependencies <-
fetchExecutableDependencies maybeTree (appSettingsDevDependencies settings)
>>= buildDependencies buildPrefix compilerSettings
mapM_
(\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name, executableDependencies = dependencies } ->
do
localDependencies <-
fetchExecutableDependencies maybeTree dependencies
>>= buildDependencies buildPrefix compilerSettings
buildProgram
sourceDir
( (map fst executableDepends)
++ (map fst devDependencies)
++ (map fst localDependencies)
)
[".f90", ".f", ".F", ".F90", ".f95", ".f03"]
(buildPrefix </> sourceDir)
compilerSettings
name
mainFile
( (map snd executableDepends)
++ (map snd devDependencies)
++ (map snd localDependencies)
)
)
examples
mapM_
(\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name, executableDependencies = dependencies } ->
do
Expand Down Expand Up @@ -410,6 +445,10 @@ runArguments =
( long "release"
<> help "Build with optimizations instead of debugging"
)
<*> switch
( long "example"
<> help "Run example programs instead of applications"
)
<*> strOption
( long "compiler"
<> metavar "COMPILER"
Expand Down Expand Up @@ -503,6 +542,8 @@ settingsCodec =
.= tomlSettingsLibrary
<*> Toml.list executableCodec "executable"
.= tomlSettingsExecutables
<*> Toml.list executableCodec "example"
.= tomlSettingsExamples
<*> Toml.list executableCodec "test"
.= tomlSettingsTests
<*> Toml.tableMap Toml._KeyString versionCodec "dependencies"
Expand Down Expand Up @@ -608,6 +649,7 @@ toml2AppSettings tomlSettings args = do
executableSettings <- getExecutableSettings
(tomlSettingsExecutables tomlSettings)
projectName
exampleSettings <- getExampleSettings $ tomlSettingsExamples tomlSettings
testSettings <- getTestSettings $ tomlSettingsTests tomlSettings
compilerSettings <- defineCompilerSettings specifiedFlags compiler release
buildPrefix <- makeBuildPrefix (compilerSettingsCompiler compilerSettings)
Expand All @@ -619,6 +661,7 @@ toml2AppSettings tomlSettings args = do
, appSettingsBuildPrefix = buildPrefix
, appSettingsLibrary = librarySettings
, appSettingsExecutables = executableSettings
, appSettingsExamples = exampleSettings
, appSettingsTests = testSettings
, appSettingsDependencies = dependencies
, appSettingsDevDependencies = devDependencies
Expand Down Expand Up @@ -725,6 +768,24 @@ getExecutableSettings [] projectName = do
else return []
getExecutableSettings executables _ = return executables

getExampleSettings :: [Executable] -> IO [Executable]
getExampleSettings [] = do
defaultDirectoryExists <- doesDirectoryExist "example"
if defaultDirectoryExists
then do
defaultMainExists <- doesFileExist ("example" </> "main.f90")
if defaultMainExists
then return
[ Executable { executableSourceDir = "example"
, executableMainFile = "main.f90"
, executableName = "demo"
, executableDependencies = Map.empty
}
]
else return []
else return []
getExampleSettings examples = return examples

getTestSettings :: [Executable] -> IO [Executable]
getTestSettings [] = do
defaultDirectoryExists <- doesDirectoryExist "test"
Expand Down
15 changes: 15 additions & 0 deletions bootstrap/test/Spec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ testHelloWorld :: IO ()
testHelloWorld =
withCurrentDirectory (example_path </> "hello_world") $ start $ Run
{ runRelease = False
, runExample = False
, runCompiler = "gfortran"
, runFlags = []
, runRunner = Nothing
Expand All @@ -42,6 +43,19 @@ testHelloFpm :: IO ()
testHelloFpm =
withCurrentDirectory (example_path </> "hello_fpm") $ start $ Run
{ runRelease = False
, runExample = False
, runCompiler = "gfortran"
, runFlags = []
, runRunner = Nothing
, runTarget = Nothing
, runArgs = Nothing
}

testWithExamples :: IO ()
testWithExamples =
withCurrentDirectory (example_path </> "with_examples") $ start $ Run
{ runRelease = False
, runExample = True
, runCompiler = "gfortran"
, runFlags = []
, runRunner = Nothing
Expand Down Expand Up @@ -72,6 +86,7 @@ testMakefileComplex :: IO ()
testMakefileComplex =
withCurrentDirectory (example_path </> "makefile_complex") $ start $ Run
{ runRelease = False
, runExample = False
, runCompiler = "gfortran"
, runFlags = []
, runRunner = Nothing
Expand Down
13 changes: 12 additions & 1 deletion ci/run_tests.bat
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,17 @@ if errorlevel 1 exit 1
.\build\gfortran_debug\test\farewell_test


cd ..\with_examples
if errorlevel 1 exit 1

del /q /f build
%fpm_path% build
if errorlevel 1 exit 1

.\build\gfortran_debug\app\demo-prog
if errorlevel 1 exit 1


cd ..\auto_discovery_off
if errorlevel 1 exit 1

Expand Down Expand Up @@ -167,4 +178,4 @@ if errorlevel 1 exit 1
.\build\gfortran_debug\app\gomp_test
if errorlevel 1 exit 1

cd ..\..
cd ..\..
6 changes: 5 additions & 1 deletion ci/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ cd ../hello_complex_2
./build/gfortran_debug/test/greet_test
./build/gfortran_debug/test/farewell_test

cd ../with_examples
"${f_fpm_path}" build
./build/gfortran_debug/app/demo-prog

cd ../auto_discovery_off
"${f_fpm_path}" build
./build/gfortran_debug/app/auto_discovery_off
Expand Down Expand Up @@ -77,4 +81,4 @@ cd ../link_executable
./build/gfortran_debug/app/gomp_test

# Cleanup
rm -rf ./*/build
rm -rf ./*/build
1 change: 1 addition & 0 deletions example_packages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ the features demonstrated in each package and which versions of fpm are supporte
| hello_complex_2 | Auto-discovery of tests and executables with modules | N | Y |
| hello_fpm | App-only; local path dependency | Y | Y |
| hello_world | App-only | Y | Y |
| with_examples | Example-only | Y | Y |
| makefile_complex | External build command (makefile); local path dependency | Y | N |
| program_with_module | App-only; module+program in single source file | Y | Y |
| submodules | Lib-only; submodules (3 levels) | N | Y |
Expand Down
1 change: 1 addition & 0 deletions example_packages/with_examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build/*
3 changes: 3 additions & 0 deletions example_packages/with_examples/demo/prog.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
program demo
write(*, '(a)') "This is a simple demo program, but not a real application"
end program demo
7 changes: 7 additions & 0 deletions example_packages/with_examples/fpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name = "with_examples"
build.auto-examples = false

[[example]]
name = "demo-prog"
source-dir = "demo"
main = "prog.f90"
36 changes: 30 additions & 6 deletions fpm/src/fpm.f90
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ module fpm
use fpm_environment, only: run
use fpm_filesystem, only: is_dir, join_path, number_of_rows, list_files, exists, basename
use fpm_model, only: fpm_model_t, srcfile_t, build_target_t, &
FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, &
FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST, &
FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, FPM_SCOPE_DEP, &
FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST, &
FPM_TARGET_EXECUTABLE, FPM_TARGET_ARCHIVE
use fpm_compiler, only: add_compile_flag_defaults

Expand Down Expand Up @@ -85,6 +85,15 @@ subroutine build_model(model, settings, package, error)
return
end if

end if
if (is_dir('example') .and. package%build%auto_examples) then
call add_sources_from_dir(model%sources,'example', FPM_SCOPE_EXAMPLE, &
with_executables=.true., error=error)

if (allocated(error)) then
return
end if

end if
if (is_dir('test') .and. package%build%auto_tests) then
call add_sources_from_dir(model%sources,'test', FPM_SCOPE_TEST, &
Expand All @@ -104,6 +113,16 @@ subroutine build_model(model, settings, package, error)
return
end if

end if
if (allocated(package%example)) then
call add_executable_sources(model%sources, package%example, FPM_SCOPE_EXAMPLE, &
auto_discover=package%build%auto_examples, &
error=error)

if (allocated(error)) then
return
end if

end if
if (allocated(package%test)) then
call add_executable_sources(model%sources, package%test, FPM_SCOPE_TEST, &
Expand Down Expand Up @@ -205,6 +224,7 @@ subroutine cmd_run(settings,test)
type(string_t), allocatable :: executables(:)
type(build_target_t), pointer :: exe_target
type(srcfile_t), pointer :: exe_source
integer :: run_scope

call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
if (allocated(error)) then
Expand All @@ -218,6 +238,12 @@ subroutine cmd_run(settings,test)
error stop 1
end if

if (test) then
run_scope = FPM_SCOPE_TEST
else
run_scope = merge(FPM_SCOPE_EXAMPLE, FPM_SCOPE_APP, settings%example)
end if

! Enumerate executable targets to run
col_width = -1
found(:) = .false.
Expand All @@ -231,8 +257,7 @@ subroutine cmd_run(settings,test)

exe_source => exe_target%dependencies(1)%ptr%source

if (exe_source%unit_scope == &
merge(FPM_SCOPE_TEST,FPM_SCOPE_APP,test)) then
if (exe_source%unit_scope == run_scope) then

col_width = max(col_width,len(basename(exe_target%output_file))+2)

Expand Down Expand Up @@ -295,8 +320,7 @@ subroutine cmd_run(settings,test)

exe_source => exe_target%dependencies(1)%ptr%source

if (exe_source%unit_scope == &
merge(FPM_SCOPE_TEST,FPM_SCOPE_APP,test)) then
if (exe_source%unit_scope == run_scope) then

write(stderr,'(A)',advance=(merge("yes","no ",modulo(j,nCol)==0))) &
& [character(len=col_width) :: basename(exe_target%output_file)]
Expand Down
10 changes: 10 additions & 0 deletions fpm/src/fpm/dependency.f90
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,16 @@ recursive subroutine add_project_dependencies(self, package, root, main, error)
if (allocated(error)) return
end if

if (allocated(package%example)) then
do ii = 1, size(package%example)
if (allocated(package%example(ii)%dependency)) then
call self%add(package%example(ii)%dependency, error)
if (allocated(error)) exit
end if
end do
if (allocated(error)) return
end if

if (allocated(package%test)) then
do ii = 1, size(package%test)
if (allocated(package%test(ii)%dependency)) then
Expand Down
Loading