Skip to content
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

Compiler flags profiles #498

Open
wants to merge 38 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
ee0d46c
Initial branch commit - new_package subroutine parses TOML and loads …
kubajj May 31, 2021
a978be3
Add support for profiles defined with missing values
kubajj Jun 1, 2021
648764c
Add first implementation of find_profile subroutine
kubajj Jun 3, 2021
e8ea449
Temporary solution of adding compiler flags from profile to model
kubajj Jun 3, 2021
020c34a
Added built in profiles support, updated find_profile decision making
kubajj Jun 4, 2021
1caa897
Add error handling and basic testing for profiles
kubajj Jun 8, 2021
97085c6
Fix merge conflict
kubajj Jun 10, 2021
507d634
Simplify profiles handling before implementing package scope
kubajj Jun 11, 2021
5550bf7
Initial implementation of package scope compiler profiles
kubajj Jun 15, 2021
941c23b
Add file scope flags and representation of profiles as string for sho…
kubajj Jun 18, 2021
a1a503c
Change _ to - in toml fields names, minor changes in get_flags subrou…
kubajj Jun 21, 2021
f81132a
Merge pull requests
kubajj Jun 24, 2021
2989997
Add example pacakges with compiler profiles, remove c_flags from srcf…
kubajj Jun 28, 2021
709ad3a
Add an example project with c flags
kubajj Jun 28, 2021
0997172
Stop modifying model outside of build_model
kubajj Jun 30, 2021
cb06c00
Fix src/fpm_targets.f90 to run with no source files
kubajj Jul 22, 2021
cab4181
Fix merge conflicts
kubajj Jul 22, 2021
286ac9c
Remove failing line from fpm_targets.f90
kubajj Jul 22, 2021
98badd6
Update error handling in profiles parser and introduce is_built_in bo…
kubajj Jul 26, 2021
7d8ca4c
Add profiles hierarchy and propagation to dependencies
kubajj Jul 31, 2021
999c3a6
Implement suggested changes
kubajj Jul 31, 2021
981df56
Update ci test for windows
kubajj Jul 31, 2021
1e82f4e
Update profiles priorities test to use proprocessor
kubajj Jul 31, 2021
20084fe
Apply suggestions from code review
kubajj Jul 31, 2021
91323bf
Change stop to stop 1 in profiles_priorities example package
kubajj Jul 31, 2021
269416a
Prevent main package in profiles priorities from failing due to not b…
kubajj Jul 31, 2021
ba2c812
Fix merge conflict
kubajj Aug 9, 2021
ce59082
Add comments detailing the functions
kubajj Aug 9, 2021
789d823
Fox merge conflict with PR #533
kubajj Aug 9, 2021
794cd85
Apply suggestions from code review
kubajj Aug 9, 2021
a3978b8
Make new_dependency_node pure
kubajj Aug 9, 2021
e642a14
Make get_default_profiles neater
kubajj Aug 9, 2021
09e5b97
Apply some suggestions from code review
kubajj Aug 10, 2021
7d09b4f
Extend subroutine get_object_name
kubajj Aug 10, 2021
789175f
Merge branch 'Load_compiler_profiles' of github.com:kubajj/fpm into L…
kubajj Aug 10, 2021
d708b94
Close code fence and propagate error while reading manifest
kubajj Aug 10, 2021
fa52c0a
Cover invalid toml - only supported tables and fields are valid
kubajj Aug 12, 2021
1edf2f1
Last GSoC commit - Separate validation and reading when parsing toml …
kubajj Aug 13, 2021
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
32 changes: 32 additions & 0 deletions manifest-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Every manifest file consists of the following sections:
Project library dependencies
- [*dev-dependencies*](#development-dependencies):
Dependencies only needed for tests
- [*compiler profiles*](#compiler-flags-profiles):
- [*install*](#installation-configuration):
Installation configuration

Expand Down Expand Up @@ -459,6 +460,37 @@ rev = "2f5eaba864ff630ba0c3791126a3f811b6e437f3"

Development dependencies allow to declare *dev-dependencies* in the manifest root, which are available to all tests but not exported with the project.

## Compiler flags profiles
Compiler flags profiles can be declared in the *profiles* table. They are organised into subtables in the following order:

| Subtable | Profile name | Compiler | Operating system |
|---|:---:|:---:|:---:|
| Example | `debug` | `gfortran` | `linux` |

There are 4 fields that can be specified for each of the profiles:
- `'flags'` - Fortran compiler flags
- `'c_flags'` - C compiler flags
- `'link_time_flags'` - Compiler flags applied at linking time to executables
- `'files'` - A subtable containing file name-flags pairs with flags applied to single source files (these overwrite profile flags)
kubajj marked this conversation as resolved.
Show resolved Hide resolved

An example of a complete table follows:
```toml
[profiles.debug.gfortran.linux]
flags = '-g -Wall'
files={"source/greet_m.f90"="-Wall -g -fcheck=all", "source/farewell_m.f90"="-Og"}
```

All the subtables can be omitted in the definition. In such case the following behaviour is applied:
- *Profile name* is omitted - Fields of this subtable are added to fields of all profiles with matching compiler and OS definitions (this is not the case for `files` field)
- *Compiler* is omitted - Compiler is set to *default* value (currently `gfortran`)
- *Operating system* is omitted - Fields of this subtable are used if and only if there is no profile with perfectly matching OS definition

Example:
- The flags field of the following profile is appended to flags fields of all profiles using `gfortran` on `linux` OS
```toml
[profiles.linux]
flags = '-g -Wall'
kubajj marked this conversation as resolved.
Show resolved Hide resolved
```
kubajj marked this conversation as resolved.
Show resolved Hide resolved

## Installation configuration

Expand Down
84 changes: 59 additions & 25 deletions src/fpm.f90
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module fpm
use fpm_command_line, only: fpm_build_settings, fpm_new_settings, &
fpm_run_settings, fpm_install_settings, fpm_test_settings
use fpm_dependency, only : new_dependency_tree
use fpm_environment, only: run, get_env
use fpm_environment, only: run, get_env, get_os_type
use fpm_filesystem, only: is_dir, join_path, number_of_rows, list_files, exists, basename
use fpm_model, only: fpm_model_t, srcfile_t, show_model, &
FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, FPM_SCOPE_DEP, &
Expand All @@ -24,6 +24,7 @@ module fpm
& stdout=>output_unit, &
& stderr=>error_unit
use fpm_manifest_dependency, only: dependency_config_t
use fpm_manifest_profile, only: profile_config_t, find_profile, DEFAULT_COMPILER
use, intrinsic :: iso_fortran_env, only: error_unit
implicit none
private
Expand All @@ -43,9 +44,10 @@ subroutine build_model(model, settings, package, error)

integer :: i, j
type(package_config_t) :: dependency
character(len=:), allocatable :: manifest, lib_dir
type(profile_config_t) :: primary_pkg_profile, current_pkg_profile
character(len=:), allocatable :: manifest, lib_dir, profile, compiler_flags

logical :: duplicates_found = .false.
logical :: duplicates_found = .false., profile_found
type(string_t) :: include_dir

model%package_name = package%name
Expand All @@ -59,27 +61,11 @@ subroutine build_model(model, settings, package, error)
if (allocated(error)) return

if(settings%compiler.eq.'')then
model%fortran_compiler = 'gfortran'
model%fortran_compiler = DEFAULT_COMPILER
else
model%fortran_compiler = settings%compiler
endif

model%archiver = get_archiver()
call get_default_c_compiler(model%fortran_compiler, model%c_compiler)
model%c_compiler = get_env('FPM_C_COMPILER',model%c_compiler)

if (is_unknown_compiler(model%fortran_compiler)) then
write(*, '(*(a:,1x))') &
"<WARN>", "Unknown compiler", model%fortran_compiler, "requested!", &
"Defaults for this compiler might be incorrect"
end if
model%output_directory = join_path('build',basename(model%fortran_compiler)//'_'//settings%build_name)

call get_module_flags(model%fortran_compiler, &
& join_path(model%output_directory,model%package_name), &
& model%fortran_compile_flags)
model%fortran_compile_flags = settings%flag // model%fortran_compile_flags

allocate(model%packages(model%deps%ndep))

! Add sources from executable directories
Expand Down Expand Up @@ -146,10 +132,11 @@ subroutine build_model(model, settings, package, error)
manifest = join_path(dep%proj_dir, "fpm.toml")

call get_package_data(dependency, manifest, error, &
apply_defaults=.true.)
apply_defaults=.true., proj_dir=dep%proj_dir)
if (allocated(error)) exit

model%packages(i)%name = dependency%name
model%packages(i)%profiles = dependency%profiles
if (.not.allocated(model%packages(i)%sources)) allocate(model%packages(i)%sources(0))

if (allocated(dependency%library)) then
Expand Down Expand Up @@ -185,19 +172,66 @@ subroutine build_model(model, settings, package, error)
end do
if (allocated(error)) return

if (.not.(trim(settings%flag).eq.'')) then
model%cmd_compile_flags = settings%flag
else
model%cmd_compile_flags = ''
end if

if (settings%verbose) then
write(*,*)'<INFO> BUILD_NAME: ',settings%build_name
write(*,*)'<INFO> COMPILER: ',settings%compiler
write(*,*)'<INFO> C COMPILER: ',model%c_compiler
write(*,*)'<INFO> COMPILER OPTIONS: ', model%fortran_compile_flags
write(*,*)'<INFO> INCLUDE DIRECTORIES: [', string_cat(model%include_dirs,','),']'
write(*,*)'<INFO> COMMAND LINE COMPILER OPTIONS: ', model%cmd_compile_flags
! write(*,*)'<INFO> INCLUDE DIRECTORIES: [', string_cat(model%include_dirs,','),']'
end if

! Check for duplicate modules
call check_modules_for_duplicates(model, duplicates_found)
if (duplicates_found) then
error stop 'Error: One or more duplicate module names found.'
error stop 'Error: One or more duplicate module names found.'
end if

! Compiler flags logic
if(settings%profile.eq.'')then
if (trim(settings%flag).eq.'') then
profile = 'debug'
end if
else
profile = settings%profile
endif

if (allocated(profile)) then
do i=1,size(model%packages)
associate(pkg => model%packages(i))
if (allocated(pkg%profiles)) then
call find_profile(pkg%profiles, profile, model%fortran_compiler, &
& get_os_type(), profile_found, current_pkg_profile)
if (.not.profile_found .and. i.gt.1) then
current_pkg_profile = primary_pkg_profile
else if (i.eq.1) then
if (.not.profile_found) then
error stop 'Error: primary package does not have given profile.'
end if
primary_pkg_profile = current_pkg_profile
end if
else
current_pkg_profile = primary_pkg_profile
end if
pkg%chosen_profile = current_pkg_profile
end associate
end do
end if

model%archiver = get_archiver()
call get_default_c_compiler(model%fortran_compiler, model%c_compiler)
model%c_compiler = get_env('FPM_C_COMPILER',model%c_compiler)

if (is_unknown_compiler(model%fortran_compiler)) then
write(*, '(*(a:,1x))') &
"<WARN>", "Unknown compiler", model%fortran_compiler, "requested!", &
"Defaults for this compiler might be incorrect"
end if

end subroutine build_model

! Check for duplicate modules
Expand Down
12 changes: 9 additions & 3 deletions src/fpm/manifest.f90
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ end subroutine default_test


!> Obtain package meta data from a configuation file
subroutine get_package_data(package, file, error, apply_defaults)
subroutine get_package_data(package, file, error, apply_defaults, proj_dir)

!> Parsed package meta data
type(package_config_t), intent(out) :: package
Expand All @@ -102,6 +102,9 @@ subroutine get_package_data(package, file, error, apply_defaults)
!> Apply package defaults (uses file system operations)
logical, intent(in), optional :: apply_defaults

!> Path to project directory of the current package
character(len=*), intent(in), optional :: proj_dir

type(toml_table), allocatable :: table
character(len=:), allocatable :: root

Expand All @@ -112,8 +115,11 @@ subroutine get_package_data(package, file, error, apply_defaults)
call fatal_error(error, "Unclassified error while reading: '"//file//"'")
return
end if

call new_package(package, table, error)
if (present(proj_dir)) then
call new_package(package, table, error, proj_dir)
else
call new_package(package, table, error)
end if
if (allocated(error)) return

if (present(apply_defaults)) then
Expand Down
34 changes: 31 additions & 3 deletions src/fpm/manifest/package.f90
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
module fpm_manifest_package
use fpm_manifest_build, only: build_config_t, new_build_config
use fpm_manifest_dependency, only : dependency_config_t, new_dependencies
use fpm_manifest_profile, only : profile_config_t, new_profiles, get_default_profiles
use fpm_manifest_example, only : example_config_t, new_example
use fpm_manifest_executable, only : executable_config_t, new_executable
use fpm_manifest_library, only : library_config_t, new_library
Expand All @@ -42,6 +43,7 @@ module fpm_manifest_package
use fpm_toml, only : toml_table, toml_array, toml_key, toml_stat, get_value, &
& len
use fpm_versioning, only : version_t, new_version
use fpm_filesystem, only: join_path
implicit none
private

Expand Down Expand Up @@ -81,6 +83,9 @@ module fpm_manifest_package
!> Development dependency meta data
type(dependency_config_t), allocatable :: dev_dependency(:)

!> Profiles meta data
type(profile_config_t), allocatable :: profiles(:)

!> Example meta data
type(example_config_t), allocatable :: example(:)

Expand All @@ -99,7 +104,7 @@ module fpm_manifest_package


!> Construct a new package configuration from a TOML data structure
subroutine new_package(self, table, error)
subroutine new_package(self, table, error, proj_dir)

!> Instance of the package configuration
type(package_config_t), intent(out) :: self
Expand All @@ -110,13 +115,16 @@ subroutine new_package(self, table, error)
!> Error handling
type(error_t), allocatable, intent(out) :: error

!> Path to project directory of the current package
character(len=*), intent(in), optional :: proj_dir

! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage
! return (13) are invalid in package names
character(len=*), parameter :: invalid_chars = &
achar(8) // achar(9) // achar(10) // achar(12) // achar(13)
type(toml_table), pointer :: child, node
type(toml_array), pointer :: children
character(len=:), allocatable :: version
character(len=:), allocatable :: version, file_scope_path
integer :: ii, nn, stat

call check(table, error)
Expand Down Expand Up @@ -177,6 +185,17 @@ subroutine new_package(self, table, error)
call new_library(self%library, child, error)
if (allocated(error)) return
end if

call get_value(table, "profiles", child, requested=.false.)
file_scope_path = ""
if (associated(child)) then
if (present(proj_dir)) file_scope_path = proj_dir
call new_profiles(self%profiles, child, error, file_scope_path)
if (allocated(error)) return
else
self%profiles = get_default_profiles(error)
if (allocated(error)) return
end if

call get_value(table, "executable", children, requested=.false.)
if (associated(children)) then
Expand Down Expand Up @@ -276,7 +295,7 @@ subroutine check(table, error)

case("version", "license", "author", "maintainer", "copyright", &
& "description", "keywords", "categories", "homepage", "build", &
& "dependencies", "dev-dependencies", "test", "executable", &
& "dependencies", "dev-dependencies", "profiles", "test", "executable", &
& "example", "library", "install")
continue

Expand Down Expand Up @@ -373,6 +392,15 @@ subroutine info(self, unit, verbosity)
call self%dev_dependency(ii)%info(unit, pr - 1)
end do
end if

if (allocated(self%profiles)) then
if (size(self%profiles) > 1 .or. pr > 2) then
write(unit, fmti) "- profiles", size(self%profiles)
end if
do ii = 1, size(self%profiles)
call self%profiles(ii)%info(unit, pr - 1)
end do
end if

end subroutine info

Expand Down
Loading