Skip to content
Open
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
48be4a2
profiles: remove all previous fields; replace with a list of features
perazz Sep 7, 2025
5f6f5d1
test profiles serialization
perazz Sep 7, 2025
1c37b21
remove .features field from the profiles manifest
perazz Sep 7, 2025
f7790cd
add `features` to the CLI settings
perazz Sep 7, 2025
698e9ce
CLI features: make it a string array
perazz Sep 7, 2025
152e4ca
add CLI tests
perazz Sep 7, 2025
b3a97c4
implement default profiles
perazz Sep 7, 2025
bbbec6a
validate profiles; add default "debug" and "release"
perazz Sep 7, 2025
9c4cac1
feature collection: extend export_config
perazz Sep 7, 2025
1f4a489
merge features into package configuration
perazz Sep 7, 2025
07988e1
implement features in the dependency config
perazz Sep 7, 2025
cc73d56
apply features to the dependency config
perazz Sep 7, 2025
546482b
test dependency propagation
perazz Sep 7, 2025
f2bb830
fix profile/feature CLI
perazz Sep 7, 2025
9449c6e
add tests on invalid chains
perazz Sep 8, 2025
258f35c
fix merging of preprocessor collections
perazz Sep 8, 2025
6efba86
test merging of preprocessor collections
perazz Sep 8, 2025
9beb972
ensure metapackage names are always set
perazz Sep 8, 2025
6ff7d70
do not allow multiple definitions
perazz Sep 8, 2025
d748c92
preprocessing fix: must be on if *any* features - even not active - h…
perazz Sep 8, 2025
cf4a704
fix
perazz Sep 8, 2025
f3356a7
Update test_features.f90
perazz Sep 8, 2025
a117115
generalize test for windows
perazz Sep 8, 2025
663fa0f
intel fix
perazz Sep 8, 2025
a4b3614
fix
perazz Sep 8, 2025
81af006
create features test
perazz Sep 8, 2025
2c2159f
add macos fix
perazz Sep 8, 2025
ca94a39
fix features test
perazz Sep 8, 2025
9ec4ebb
fix most tests
perazz Sep 8, 2025
8e37737
update features_with_dependency test
perazz Sep 9, 2025
270f102
Merge branch 'main' into features_application
perazz Sep 11, 2025
1a1676f
intel fix: do not access unallocated `flags`
perazz Sep 11, 2025
1135492
typo
perazz Sep 11, 2025
e83c1c6
deactivate blank case
perazz Sep 11, 2025
dcca0fe
metapackage fix: clean before reading manifest, not after; refactor i…
perazz Sep 11, 2025
1c664a7
gcc-15 fix
perazz Sep 11, 2025
6ae0ba1
intel fix: change program name
perazz Sep 11, 2025
4af88df
Update src/fpm_targets.f90
perazz Sep 15, 2025
2e94e79
fix example
perazz Sep 21, 2025
d5ca48a
generalize compile flags
perazz Sep 21, 2025
f556321
new test: compiler flags
perazz Sep 21, 2025
acb7f34
example package: features_per_compiler
perazz Sep 21, 2025
b1942b5
do not check `=native`: it is unrolled by gfortran
perazz Sep 21, 2025
dd363fb
Merge branch 'main' into features_application
perazz Sep 24, 2025
cb2e5fc
Merge branch 'main' into features_application
perazz Sep 27, 2025
f847311
catch error messages correctly
perazz Sep 27, 2025
cc75c63
adjust feature test
perazz Sep 27, 2025
86653e6
ensure `-fPIC` with llvm_unknown
perazz Sep 27, 2025
c112e6f
use allocatable
perazz Sep 27, 2025
670c67f
more gcc-15 array initializer fixes
perazz Sep 27, 2025
db45d55
better identify debug flags
perazz Sep 27, 2025
ad69e28
gcc-10 fix: explicit character allocation
perazz Sep 27, 2025
b587fdf
ifx crash: fix `fPIC` logic
perazz Sep 28, 2025
fc5f5c4
debug print
perazz Sep 28, 2025
a9d702d
Update platform.f90
perazz Sep 28, 2025
0ae4f8e
more output
perazz Sep 28, 2025
4551e49
Update feature_collection.f90
perazz Sep 28, 2025
150bca5
ifx 2025.2
perazz Sep 28, 2025
c3b16be
avoid `xHost` on Intel compilers
perazz Sep 28, 2025
bf8757c
do not use `-fast` on `ifx`
perazz Sep 28, 2025
4f21bf2
Update main.f90
perazz Sep 28, 2025
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
4 changes: 2 additions & 2 deletions ci/meta_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ pushd metapackage_stdlib
popd

pushd metapackage_minpack
"$fpm" build --verbose
"$fpm" run --verbose
"$fpm" build --verbose --flag " -Wno-external-argument-mismatch"
"$fpm" run --verbose --flag " -Wno-external-argument-mismatch"
popd

pushd metapackage_mpi
Expand Down
4 changes: 4 additions & 0 deletions ci/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -374,5 +374,9 @@ popd
# Test custom build directory functionality
bash "../ci/test_custom_build_dir.sh" "$fpm" hello_world

# Test FPM features functionality
echo "=== Testing FPM Features Functionality ==="
bash "../ci/test_features.sh" "$fpm"

# Cleanup
rm -rf ./*/build
164 changes: 164 additions & 0 deletions ci/test_features.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/usr/bin/env bash
set -ex

# Test script for FPM features functionality
# Usage: ./test_features.sh [fpm_executable]
# Note: This script should be run from the repo root or integrated into run_tests.sh

if [ "$1" ]; then
fpm="$1"
else
# Default to the fpm passed from run_tests.sh or system fpm
fpm="${fpm:-fpm}"
fi

echo "Testing FPM features functionality"

echo "=== Testing features_demo package ==="

# Test 1: Basic features - debug feature
pushd "features_demo"
echo "Test 1: Basic debug feature"
rm -rf build
"$fpm" run --features debug | tee output.txt
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled"; exit 1; }
echo "✓ Debug feature works"

# Test 2: Profile usage - development profile (includes debug)
echo "Test 2: Development profile (debug feature)"
rm -rf build
"$fpm" run --profile development --target features_demo | tee output.txt
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled in development profile"; exit 1; }
echo "✓ Development profile works"

# Test 3: Multiple features
echo "Test 3: Multiple features (debug + openmp)"
rm -rf build
"$fpm" run --features debug,openmp --target features_demo | tee output.txt
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled with multiple features"; exit 1; }
grep -q "OpenMP support enabled" output.txt || { echo "ERROR: OpenMP not enabled with multiple features"; exit 1; }
echo "✓ Multiple features work"

# Test 4: Feature-specific executable (debug_demo only available with debug feature)
echo "Test 4: Feature-specific executable"
rm -rf build
"$fpm" run --features debug --target debug_demo | tee output.txt
grep -q "Debug Demo Program" output.txt || { echo "ERROR: Debug Demo Program not found"; exit 1; }
grep -q "Debug mode: ON" output.txt || { echo "ERROR: Debug mode not ON in debug_demo"; exit 1; }
echo "✓ Feature-specific executable works"

# Test 5: Profile with multiple features - production profile (release + openmp)
echo "Test 5: Production profile (release + openmp)"
rm -rf build
"$fpm" run --profile production --target features_demo | tee output.txt
grep -q "RELEASE mode enabled" output.txt || { echo "ERROR: RELEASE mode not enabled in production profile"; exit 1; }
grep -q "OpenMP support enabled" output.txt || { echo "ERROR: OpenMP not enabled in production profile"; exit 1; }
# Should NOT have debug
if grep -q "DEBUG mode enabled" output.txt; then
echo "ERROR: DEBUG mode should not be enabled in production profile"
exit 1
fi
echo "✓ Production profile works"

# Test 6: No features - baseline behavior
echo "Test 6: No features (baseline)"
rm -rf build
"$fpm" run --target features_demo | tee output.txt
# Should have neither DEBUG nor RELEASE without explicit features
if grep -q "DEBUG mode enabled" output.txt; then
echo "ERROR: DEBUG mode should not be enabled in baseline"
exit 1
fi
if grep -q "RELEASE mode enabled" output.txt; then
echo "ERROR: RELEASE mode should not be enabled in baseline"
exit 1
fi
if ! grep -q "Features: NONE" output.txt && ! grep -q "Demo completed successfully" output.txt; then
echo "ERROR: Expected baseline features output not found"
exit 1
fi
echo "✓ Baseline (no features) works"

# Test 7: Error handling - invalid feature
echo "Test 7: Error handling for invalid feature"
rm -rf build
if ! "$fpm" run --features nonexistent --target features_demo > /dev/null 2>&1; then
echo "Correctly rejected invalid feature"
else
echo "ERROR: Should reject invalid feature" && exit 1
fi

# Test 8: Error handling - invalid profile
echo "Test 8: Error handling for invalid profile"
rm -rf build
if ! "$fpm" run --profile nonexistent --target features_demo > /dev/null 2>&1; then
echo "Correctly rejected invalid profile"
else
echo "ERROR: Should reject invalid profile" && exit 1
fi

# Test 9: Features and profile mutual exclusion
echo "Test 9: Features and profile mutual exclusion"
rm -rf build
if ! "$fpm" run --features debug --profile development --target features_demo > /dev/null 2>&1; then
echo "Correctly rejected features + profile combination"
else
echo "ERROR: Should reject features + profile combination" && exit 1
fi

# Cleanup
rm -rf build output.txt build_list.txt
popd

echo "=== Testing features_with_dependency package ==="

# Test dependency features
pushd "features_with_dependency"

# RE-ENABLE AFTER MERGING fpm WITH CPP PARSING PR
# Test 10: No features - should show NONE for both local and dependency
# echo "Test 10: Dependency package without features"
rm -rf build
#"$fpm" run | tee output.txt
# grep -q "NONE - no local features active" output.txt || { echo "ERROR: Local features NONE message not found"; exit 1; }
# grep -q "Features: NONE" output.txt || { echo "ERROR: Features NONE not found in dependency test"; exit 1; }
# echo "✓ Dependency package baseline works"

# Test 11: Debug dependency feature
echo "Test 11: Debug dependency feature"
rm -rf build
"$fpm" run --features with_feat_debug | tee output.txt
grep -q "WITH_DEBUG_DEPENDENCY" output.txt || { echo "ERROR: WITH_DEBUG_DEPENDENCY not found"; exit 1; }
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled in dependency test"; exit 1; }
echo "✓ Debug dependency feature works"

# Test 12: Release dependency feature
echo "Test 12: Release dependency feature"
rm -rf build
"$fpm" run --features with_feat_release | tee output.txt
grep -q "WITH_RELEASE_DEPENDENCY" output.txt || { echo "ERROR: WITH_RELEASE_DEPENDENCY not found"; exit 1; }
grep -q "RELEASE mode enabled" output.txt || { echo "ERROR: RELEASE mode not enabled in dependency test"; exit 1; }
echo "✓ Release dependency feature works"

# Test 13: Multi dependency feature
echo "Test 13: Multi dependency feature"
rm -rf build
"$fpm" run --features with_feat_multi | tee output.txt
grep -q "WITH_MULTI_DEPENDENCY" output.txt || { echo "ERROR: WITH_MULTI_DEPENDENCY not found"; exit 1; }
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled in multi dependency test"; exit 1; }
grep -q "MPI support enabled" output.txt || { echo "ERROR: MPI support not enabled in multi dependency test"; exit 1; }
echo "✓ Multi dependency feature works"

# Test 14: Profile with dependency features
echo "Test 14: Debug dependency profile"
rm -rf build
"$fpm" run --profile debug_dep | tee output.txt
grep -q "WITH_DEBUG_DEPENDENCY" output.txt || { echo "ERROR: WITH_DEBUG_DEPENDENCY not found in profile test"; exit 1; }
grep -q "DEBUG mode enabled" output.txt || { echo "ERROR: DEBUG mode not enabled in dependency profile test"; exit 1; }
echo "✓ Debug dependency profile works"

# Cleanup
rm -rf build output.txt
popd

echo "All FPM features tests passed!"
16 changes: 16 additions & 0 deletions example_packages/features_demo/app/debug_demo.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
program debug_demo
use features_demo
implicit none

write(*,*) 'Debug Demo Program'
write(*,*) '=================='

#ifdef DEBUG
write(*,*) 'Debug mode: ON'
#else
write(*,*) 'Debug mode: OFF'
#endif

call show_features()

end program debug_demo
12 changes: 12 additions & 0 deletions example_packages/features_demo/app/main.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
program main
use features_demo
implicit none

call show_features()

write(*,*) ''
write(*,*) get_build_info()
write(*,*) ''
write(*,*) 'Demo completed successfully!'

end program main
35 changes: 35 additions & 0 deletions example_packages/features_demo/fpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name = "features_demo"
version = "0.1.0"
license = "MIT"
description = "Demo package for FPM features functionality"

[[executable]]
name = "features_demo"
source-dir = "app"
main = "main.f90"

[features]
# Base debug feature
debug.flags = "-g"
debug.preprocess.cpp.macros = "DEBUG"

# Release feature
release.flags = "-O3"
release.preprocess.cpp.macros = "RELEASE"

# Compiler-specific features
debug.gfortran.flags = "-Wall -fcheck=bounds"
release.gfortran.flags = "-march=native"

# Platform-specific features
linux.preprocess.cpp.macros = "LINUX_BUILD"

# Parallel features
mpi.preprocess.cpp.macros = "USE_MPI"
mpi.dependencies.mpi = "*"
openmp.preprocess.cpp.macros = "USE_OPENMP"
openmp.dependencies.openmp = "*"

[profiles]
development = ["debug"]
production = ["release", "openmp"]
78 changes: 78 additions & 0 deletions example_packages/features_demo/src/features_demo.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
module features_demo
implicit none
private
public :: show_features, get_build_info

contains

!> Display which features are enabled
subroutine show_features()
write(*,*) 'FPM Features Demo'
write(*,*) '================='

! Debug/Release flags
#ifdef DEBUG
write(*,*) '✓ DEBUG mode enabled'
#endif
#ifdef RELEASE
write(*,*) '✓ RELEASE mode enabled'
#endif

! Platform detection
#ifdef LINUX_BUILD
write(*,*) '✓ Linux platform detected'
#endif
#ifdef WINDOWS_BUILD
write(*,*) '✓ Windows platform detected'
#endif

! Parallel features
#ifdef USE_MPI
write(*,*) '✓ MPI support enabled'
#endif
#ifdef USE_OPENMP
write(*,*) '✓ OpenMP support enabled'
#endif

! Compiler info (if available)
write(*,*) 'Build configuration:'
call show_compiler_info()

end subroutine show_features

!> Show compiler information
subroutine show_compiler_info()
#ifdef __GFORTRAN__
write(*,*) ' - Compiler: GNU Fortran'
#endif
#ifdef __INTEL_COMPILER
write(*,*) ' - Compiler: Intel Fortran'
#endif
end subroutine show_compiler_info

!> Get build information as a string
function get_build_info() result(info)
character(len=200) :: info

info = 'Features: '

#ifdef DEBUG
info = trim(info) // 'DEBUG '
#endif
#ifdef RELEASE
info = trim(info) // 'RELEASE '
#endif
#ifdef USE_MPI
info = trim(info) // 'MPI '
#endif
#ifdef USE_OPENMP
info = trim(info) // 'OPENMP '
#endif

if (len_trim(info) == 10) then ! Only "Features: "
info = trim(info) // 'NONE'
end if

end function get_build_info

end module features_demo
13 changes: 13 additions & 0 deletions example_packages/features_with_dependency/app/main.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
program features_with_dependency_demo
use features_with_dependency, only: show_features
implicit none

print *, "=== Features with Dependency Demo ==="
print *, ""

call show_features()

print *, ""
print *, "This demonstrates feature propagation to dependencies."

end program features_with_dependency_demo
40 changes: 40 additions & 0 deletions example_packages/features_with_dependency/fpm.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name = "features_with_dependency"
version = "0.1.0"
license = "MIT"
description = "Demo package testing dependency features"

[[executable]]
name = "features_with_dependency"
source-dir = "app"
main = "main.f90"

[dependencies]
# Base dependencies (none for this demo - features will add them)

[features]
# Feature that enables debug mode in the dependency
with_feat_debug.dependencies.features_demo = { path = "../features_demo", features = ["debug"] }
with_feat_debug.preprocess.cpp.macros = ["WITH_DEMO","WITH_DEBUG_DEPENDENCY"]

# Feature that enables release mode in the dependency
with_feat_release.dependencies.features_demo = { path = "../features_demo", features = ["release"] }
with_feat_release.preprocess.cpp.macros = ["WITH_DEMO","WITH_RELEASE_DEPENDENCY"]

# Feature that enables multiple dependency features
with_feat_multi.dependencies.features_demo = { path = "../features_demo", features = ["debug", "mpi"] }
with_feat_multi.preprocess.cpp.macros = ["WITH_DEMO","WITH_MULTI_DEPENDENCY"]

# Feature for platform-specific dependency features
linux_specific.linux.dependencies.features_demo = { path = "../features_demo", features = ["linux"] }
linux_specific.preprocess.cpp.macros = ["WITH_DEMO","LINUX_FEATURES"]

# Feature combining compiler and dependency features
gfortran_optimized.gfortran.dependencies.features_demo = { path = "../features_demo", features = ["release", "gfortran"] }
gfortran_optimized.gfortran.flags = "-O3 -march=native"
gfortran_optimized.preprocess.cpp.macros = ["WITH_DEMO"]


[profiles]
debug_dep = ["with_feat_debug"]
release_dep = ["with_feat_release"]
full_test = ["with_feat_multi", "linux_specific"]
Loading
Loading