Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
fbe7271
feat: add `fpm generate --cmake` command
JeffIrwin Jan 19, 2026
547d4b8
fix examples like hello_complex with multiple app executables
JeffIrwin Jan 19, 2026
d92c54b
fix dependencies
JeffIrwin Jan 19, 2026
1769465
fix: include all source files in CMake test executables
JeffIrwin Jan 19, 2026
e8b42b5
fix help test for new generate command
JeffIrwin Jan 19, 2026
679b62b
fix examples like hello_complex_2 with multiple exes and shared modules
JeffIrwin Jan 19, 2026
34d28d2
use the correct dependency path, important for local dependencies
JeffIrwin Jan 19, 2026
d082a26
fix examples like hello_fpm with dependencies but no lib of its own
JeffIrwin Jan 19, 2026
3229b5d
add cmake test script
JeffIrwin Jan 19, 2026
44cf808
detect c header files
JeffIrwin Jan 24, 2026
5e1bc43
update cmake test script with list of failed cases
JeffIrwin Jan 24, 2026
0b153c5
fix c_includes example
JeffIrwin Jan 24, 2026
9e3eb97
fix c_main example
JeffIrwin Jan 24, 2026
2feddb9
detect file extensions consistent with the rest of fpm
JeffIrwin Jan 24, 2026
1865a6e
fix c_main_preprocess example
JeffIrwin Jan 25, 2026
49b958c
fix circular example
JeffIrwin Jan 25, 2026
2058b2b
use fpm's existing target pruning infrastructure to fix dependency_pr…
JeffIrwin Jan 25, 2026
78078f9
fix regression in c_includes caused by last commit
JeffIrwin Jan 25, 2026
dbc6628
fix features_with_dependency example
JeffIrwin Jan 25, 2026
43399f3
Revert "fix features_with_dependency example"
JeffIrwin Jan 25, 2026
247e6b7
features_with_dependency is actually broken
JeffIrwin Jan 25, 2026
4c621f5
fix fixed-form example
JeffIrwin Jan 25, 2026
f323816
fix a few metapackage examples
JeffIrwin Jan 25, 2026
75d4884
fix mpi metapackage example
JeffIrwin Jan 25, 2026
4550fdd
fix linker warning about missing '--end-group' flag
JeffIrwin Jan 26, 2026
50e6686
fix c_header_only regression
JeffIrwin Jan 26, 2026
f6dfdfe
hdf5 example doesn't work yet, not sure why i thought it did
JeffIrwin Jan 26, 2026
6abecc7
a few more examples have been fixed already by other changes
JeffIrwin Jan 26, 2026
783aaa6
fix free-form example
JeffIrwin Jan 27, 2026
3c85db0
fix link_executable example
JeffIrwin Jan 27, 2026
f749468
fix CMake race condition for shared module files
JeffIrwin Jan 27, 2026
1b24b18
optimize shared module detection using hash table
JeffIrwin Jan 27, 2026
7595046
resize hash table as needed
JeffIrwin Jan 29, 2026
8a2cce6
fix '-I/path' vs '-I /path' issue for hdf5 example
JeffIrwin Jan 29, 2026
1fb7908
Fix MPI C++ linking in CMake by using language-specific link flags
JeffIrwin Jan 29, 2026
33797e4
fix preprocess_cpp example
JeffIrwin Jan 30, 2026
61afb3c
Fix preprocessing macros to apply to all languages in CMake generation
JeffIrwin Jan 30, 2026
fc982b2
Fix CMake generation to handle custom preprocessor suffixes correctly
JeffIrwin Jan 30, 2026
79b2d76
fix preprocess_cpp_deps example
JeffIrwin Jan 31, 2026
7abdf28
fix preprocess_hello example
JeffIrwin Jan 31, 2026
2befff4
Fix CMake target name conflicts with reserved names
JeffIrwin Jan 31, 2026
9b8277d
only use 'test_exe' for the cmake target name, still use 'test' for t…
JeffIrwin Jan 31, 2026
6c85614
optimize string array builder to not reallocate on every line
JeffIrwin Jan 31, 2026
098798a
Merge remote-tracking branch 'origin/main' into generate_cmake
JeffIrwin Jan 31, 2026
808018a
update help text for the 'generate' subcommand
JeffIrwin Jan 31, 2026
bd6ae38
move 'generate' help text down after 'clean' because users might not …
JeffIrwin Jan 31, 2026
d59295b
don't add 'include' dir if it doesn't exist
JeffIrwin Jan 31, 2026
7b22ba4
rename size/count/capacity
JeffIrwin Jan 31, 2026
8b4205f
refactor cmake.f90: reduce nesting and eliminate duplication
JeffIrwin Jan 31, 2026
c7378e3
eliminate O(n^2) loop for collecting used packages by building a tabl…
JeffIrwin Jan 31, 2026
3793dcb
optimize cmake.f90: eliminate O(n^2) loops for dependency filtering a…
JeffIrwin Jan 31, 2026
36b81e1
refactor most inlined hash maps to use a new string-to-int hash map type
JeffIrwin Feb 1, 2026
76a1fda
refactor dir_hash_table to use the hash map type
JeffIrwin Feb 1, 2026
3bc023a
refactor package hash table too
JeffIrwin Feb 1, 2026
52c8d37
add unit tests for cmake
JeffIrwin Feb 1, 2026
27e78b8
add integration tests for cmake generation
JeffIrwin Feb 1, 2026
c38842e
use existing directory path helpers
JeffIrwin Feb 1, 2026
eeba882
refactor: use fileopen/fileclose helpers in cmake generation
JeffIrwin Feb 1, 2026
fd1bc63
run the example package exe's built by cmake
JeffIrwin Feb 1, 2026
334c9f0
add green/red text in summary for success/failure
JeffIrwin Feb 1, 2026
91b2647
fix runtime issue in preprocess_per_dependency example
JeffIrwin Feb 1, 2026
168eb3f
fix: serialize preprocess macros in dependency cache
JeffIrwin Feb 1, 2026
8d931c4
get rid of unnecessary 'occupied' hash table member
JeffIrwin Feb 10, 2026
d9d3858
DRY up handling of source extensions like .f90, .cpp, etc.
JeffIrwin Feb 10, 2026
5c70d33
parameterize magic numbers and strings
JeffIrwin Feb 10, 2026
9d82695
remove claude's test for the non-standard .cxx extension which was re…
JeffIrwin Feb 10, 2026
e0f64e5
refactor: extract shared library-target generation in cmake.f90
JeffIrwin Feb 10, 2026
50df384
fix regression for preprocess_cpp_suffix example
JeffIrwin Feb 10, 2026
30d633c
add staleness detection for fpm-generated CMake files
JeffIrwin Feb 13, 2026
7e4bd03
enhance CMake staleness detection to track source file changes
JeffIrwin Feb 13, 2026
a94c252
don't check for 'Manifest hash'; no need for backwards compatibility …
JeffIrwin Feb 13, 2026
dbfebcc
fix: prevent CMake target collisions from circular dependencies
JeffIrwin Feb 15, 2026
6149be1
bump for ci
JeffIrwin Feb 15, 2026
6193e44
fix: initialize all allocatable fields in CMake test settings
JeffIrwin Feb 15, 2026
fa2b4e1
run cmake tests in ci/cd
JeffIrwin Feb 15, 2026
a9936ac
use the release binary for the cmake test
JeffIrwin Feb 15, 2026
db4bc0f
extend ci/cd block list with tests that work locally but require depe…
JeffIrwin Feb 15, 2026
4dd567d
fix: specify MinGW generator for CMake tests on Windows
JeffIrwin Feb 16, 2026
b505bd9
use a stylistically consistent block list
JeffIrwin Feb 16, 2026
238c65d
fix: normalize Windows backslashes to forward slashes in CMake paths
JeffIrwin Feb 16, 2026
6336081
fix comment in middle of bash line continuation
JeffIrwin Feb 16, 2026
af61d72
fix: normalize Windows backslashes in CMake include/dependency paths
JeffIrwin Feb 16, 2026
2af2801
cleanup redundant './' file path strings
JeffIrwin Feb 16, 2026
9448830
Merge remote-tracking branch 'origin/main' into generate_cmake
JeffIrwin Feb 16, 2026
63645fe
fix: address PR review feedback for cmake generation
JeffIrwin Feb 16, 2026
c8b0901
fix: address PR review feedback for cmake generation
JeffIrwin Feb 17, 2026
f454c22
fix: place object files before library flags in linker command
JeffIrwin Feb 19, 2026
c7ae421
Merge remote-tracking branch 'origin/main' into generate_cmake
JeffIrwin Feb 21, 2026
c04d756
test fpm building itself using its own generated cmake
JeffIrwin Feb 21, 2026
2568c63
Optimize CMake hash with order-independent XOR combination
JeffIrwin Feb 21, 2026
87f71dd
remove my own personal CLAUDE.md file
JeffIrwin Feb 21, 2026
dc30aec
remove unused is_in_list() function
JeffIrwin Feb 21, 2026
cb1839d
dry up duplicate summary logging code in cmake test script
JeffIrwin Feb 22, 2026
955805d
remove unused variables
JeffIrwin Feb 22, 2026
5f2eec9
remove more unused variables
JeffIrwin Feb 22, 2026
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
6 changes: 6 additions & 0 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ jobs:
run: |
ci/run_tests.sh "$PWD/${{ env.FPM_RELEASE }}"

- name: Test CMake generation
if: matrix.toolchain.version == 13
shell: bash
run: |
ci/test_cmake.sh "$PWD/${{ env.FPM_RELEASE }}"

- name: Upload artifact
uses: actions/upload-artifact@v6
with:
Expand Down
4 changes: 4 additions & 0 deletions app/main.f90
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ program main
fpm_update_settings, &
fpm_clean_settings, &
fpm_publish_settings, &
fpm_generate_settings, &
get_command_line_settings
use fpm_error, only: error_t
use fpm_filesystem, only: exists, parent_dir, join_path
Expand All @@ -20,6 +21,7 @@ program main
use fpm_cmd_new, only: cmd_new
use fpm_cmd_update, only : cmd_update
use fpm_cmd_publish, only: cmd_publish
use fpm_cmd_cmake, only: cmd_generate
use fpm_os, only: change_directory, get_current_directory

implicit none
Expand Down Expand Up @@ -88,6 +90,8 @@ program main
call cmd_clean(settings)
type is (fpm_publish_settings)
call cmd_publish(settings)
type is (fpm_generate_settings)
call cmd_generate(settings)
end select

if (allocated(project_root)) then
Expand Down
168 changes: 168 additions & 0 deletions ci/test_cmake.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!/usr/bin/env bash

# Test "fpm generate --cmake" by generating cmake for each example package and
# then building with the generated CMakeLists.txt

set -u

if [ $# -gt 0 ]; then
fpm="$1"
else
fpm=fpm
fi

build_failures=()
runtime_failures=()

print_summary_and_exit() {
echo "================================"
echo "Test Results Summary"
echo "================================"
if [[ ${#build_failures[@]} -eq 0 ]]; then
echo -e "Build failures: \033[0;32mnone\033[0m"
else
echo -e "Build failures (\033[0;31m${#build_failures[@]}\033[0m):"
printf ' %s\n' "${build_failures[@]}"
fi
echo ""
if [[ ${#runtime_failures[@]} -eq 0 ]]; then
echo -e "Runtime failures: \033[0;32mnone\033[0m"
else
echo -e "Runtime failures (\033[0;31m${#runtime_failures[@]}\033[0m):"
printf ' %s\n' "${runtime_failures[@]}"
fi
echo "================================"
total_failures=$((${#build_failures[@]} + ${#runtime_failures[@]}))
exit $total_failures
}

# Detect Windows/MSYS2 and set CMake generator accordingly
CMAKE_GENERATOR_FLAG=""
if [[ "$OSTYPE" == "msys" ]] || [[ "$OSTYPE" == "win32" ]] || [[ -n "${MSYSTEM:-}" ]]; then
# On Windows with MSYS2/MinGW, use MinGW Makefiles generator for Fortran support
CMAKE_GENERATOR_FLAG="-G \"MinGW Makefiles\""
fi

for dir in example_packages/*/ ; do

# Skip examples that don't work with cmake generation
case "$dir" in

# Does not work with "fpm build" either (intentionally or separate issue)
example_packages/features_with_dependency/ )
continue
;;

# Require external dependencies not available in CI/CD
example_packages/link_external/ | \
example_packages/metapackage_blas/ | \
example_packages/metapackage_hdf5/ | \
example_packages/metapackage_mpi/ | \
example_packages/metapackage_mpi_c/ | \
example_packages/metapackage_mpi_cpp/ | \
example_packages/metapackage_netcdf/ | \
example_packages/metapackage_stdlib_extblas/)
continue
;;
esac

pushd "$dir"

"$fpm" generate --cmake
if [[ $? -ne 0 ]] ; then
build_failures+=("$dir (fpm generate failed)")
popd
continue
fi
if [[ -n "${CMAKE_GENERATOR_FLAG}" ]]; then
eval cmake ${CMAKE_GENERATOR_FLAG} -B temp_cmake_build -S .
else
cmake -B temp_cmake_build -S .
fi
cmake --build temp_cmake_build --parallel
if [[ $? -ne 0 ]] ; then
build_failures+=("$dir")
else
# Find and run executables. Use maxdepth because dependencies like
# test-drive have executable hooks not built by us that I don't want to
# run
exes=$(find temp_cmake_build -maxdepth 1 -type f -executable)
for exe in $exes; do

[[ "$dir" == "example_packages/fpm_test_exit_code/" ]] && continue # returns 1 on purpose

if [[ -x "$exe" ]]; then
"$exe"
if [[ $? -ne 0 ]]; then
runtime_failures+=("$dir : $(basename $exe)")
fi
fi
done
fi

# Cleanup
rm -f CMakeLists.txt
rm -rf temp_cmake_build
# Clean up generated CMakeLists.txt in dependency directories
find build/dependencies -name CMakeLists.txt -delete 2>/dev/null || true

popd

done

echo "================================"
echo "Testing fpm self-generation with CMake"
echo "================================"

# Ensure dependencies are fetched first
"$fpm" build
if [[ $? -ne 0 ]] ; then
build_failures+=("fpm self-generation (fpm build failed)")
print_summary_and_exit
fi

# Generate CMakeLists.txt for fpm itself
"$fpm" generate --cmake
if [[ $? -ne 0 ]] ; then
build_failures+=("fpm self-generation (generate --cmake failed)")
# Cleanup and exit
rm -f CMakeLists.txt
find build/dependencies -name CMakeLists.txt -delete 2>/dev/null || true
print_summary_and_exit
fi

# Configure and build with CMake
if [[ -n "${CMAKE_GENERATOR_FLAG}" ]]; then
eval cmake ${CMAKE_GENERATOR_FLAG} -B temp_self_cmake_build -S .
else
cmake -B temp_self_cmake_build -S .
fi
cmake --build temp_self_cmake_build --parallel
if [[ $? -ne 0 ]] ; then
build_failures+=("fpm self-generation (cmake build failed)")
# Cleanup
rm -f CMakeLists.txt
rm -rf temp_self_cmake_build
find build/dependencies -name CMakeLists.txt -delete 2>/dev/null || true
print_summary_and_exit
fi

# Run the CMake-built test suites
echo "Running CMake-built test suites..."
for test_exe in temp_self_cmake_build/fpm-test temp_self_cmake_build/cli-test ; do
if [[ -x "$test_exe" ]]; then
"$test_exe"
if [[ $? -ne 0 ]]; then
runtime_failures+=("fpm self-generation : $(basename $test_exe)")
fi
fi
done

# Cleanup
rm -f CMakeLists.txt
rm -rf temp_self_cmake_build
find build/dependencies -name CMakeLists.txt -delete 2>/dev/null || true

echo "Self-generation test completed"

print_summary_and_exit
4 changes: 4 additions & 0 deletions example_packages/c_main_preprocess/fpm.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ name = "c_main_preprocess"
[library]
include-dir = ["src"]

[preprocess]
[preprocess.cpp]
macros = ["VAL"]

[[executable]]
name="main-c"
main="main.c"
13 changes: 13 additions & 0 deletions src/fpm.f90
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ module fpm
use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer
use fpm_environment, only: os_is_unix, get_os_type, OS_WINDOWS, OS_MACOS, get_env, set_env, delete_env
use fpm_settings, only: fpm_global_settings, get_global_settings
use fpm_cmake_check, only: check_cmake_staleness

implicit none
private
Expand Down Expand Up @@ -561,6 +562,12 @@ subroutine cmd_build(settings)
call fpm_stop(1,'*cmd_build* Model error: '//error%message)
end if

! Check if CMake files are out of date (after build_model provides source digests)
if (check_cmake_staleness(model%packages(1)%sources)) then
write(stderr, '(a)') "Warning: CMakeLists.txt is out of date with fpm.toml"
write(stderr, '(a)') " Run 'fpm generate --cmake' to regenerate"
end if

call targets_from_sources(targets, model, settings%prune, package%library, error)
if (allocated(error)) then
call fpm_stop(1,'*cmd_build* Target error: '//error%message)
Expand Down Expand Up @@ -616,6 +623,12 @@ subroutine cmd_run(settings,test)
call fpm_stop(1, '*cmd_run* Model error: '//error%message)
end if

! Check if CMake files are out of date (after build_model provides source digests)
if (check_cmake_staleness(model%packages(1)%sources)) then
write(stderr, '(a)') "Warning: CMakeLists.txt is out of date with fpm.toml"
write(stderr, '(a)') " Run 'fpm generate --cmake' to regenerate"
end if

call targets_from_sources(targets, model, settings%prune, package%library, error)
if (allocated(error)) then
call fpm_stop(1, '*cmd_run* Targets error: '//error%message)
Expand Down
Loading
Loading