File: fckit_preprocess_fypp.cmake

package info (click to toggle)
fckit 0.14.2-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 1,540 kB
  • sloc: f90: 7,737; python: 5,805; cpp: 2,202; pascal: 805; sh: 656; makefile: 66
file content (287 lines) | stat: -rw-r--r-- 11,870 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287

##############################################################################################
# fckit_target_append_fypp_args( output target )
#   Purpose:
#        From a target, assemble arguments to pass to fypp. These arguments are
#        the include flags and compile definition flags.
#   Arguments:
#        output            This argument will contain the flags as a list
#        target            The name of the target to process

function( fckit_target_append_fypp_args output target )
  unset(_args)
  set( valid_target TRUE )
  if( target MATCHES "/" )
    set( valid_target FALSE )
  endif()
  if( TARGET ${target} )
    get_target_property(target_type ${target} TYPE)
    if( target_type STREQUAL "INTERFACE_LIBRARY")
      set( valid_target FALSE )
    endif()
  endif()
  if( valid_target )
    if( CMAKE_VERSION VERSION_LESS 3.12 ) # Hopefully we can remove this soon
      foreach( include_property INCLUDE_DIRECTORIES;INTERFACE_INCLUDE_DIRECTORIES )
        set( prop "$<TARGET_PROPERTY:${target},${include_property}>" )
        list( APPEND _args "$<$<BOOL:${prop}>:-I $<JOIN:${prop}, -I >>" )
      endforeach()
      foreach( definitions_property COMPILE_DEFINITIONS;INTERFACE_COMPILE_DEFINITIONS )
        set( prop "$<TARGET_PROPERTY:${target},${definitions_property}>" )
        list( APPEND _args "$<$<BOOL:${prop}>:-D $<JOIN:${prop}, -D >>" )
      endforeach()
    else()
      foreach( include_property INCLUDE_DIRECTORIES;INTERFACE_INCLUDE_DIRECTORIES )
        set( prop "$<$<TARGET_EXISTS:${target}>:$<TARGET_PROPERTY:${target},${include_property}>>" )
        list( APPEND _args "$<$<BOOL:${prop}>:-I $<JOIN:${prop}, -I >>" )
      endforeach()
      foreach( definitions_property COMPILE_DEFINITIONS;INTERFACE_COMPILE_DEFINITIONS )
        set( prop "$<$<TARGET_EXISTS:${target}>:$<TARGET_PROPERTY:${target},${definitions_property}>>" )
        list( APPEND _args "$<$<BOOL:${prop}>:-D $<JOIN:${prop}, -D >>" )
      endforeach()
    endif()
  endif()
  # Append to output and set in parent scope
  if( _args )
    set(${output} ${${output}} ${_args} PARENT_SCOPE)
  endif()
endfunction()

##############################################################################################
# fckit_preprocess_fypp_sources( output
#                                [SOURCES file1 [file2]... ]
#                                [FYPP_ARGS arg1 [arg2]... ]
#                                [FYPP_ARGS_EXCLUDE arg1 [arg2]... ]
#                                [DEPENDS dep1 [dep2]... ] )
#    Purpose:
#        Preprocess source files with fypp
#
#    Arguments:
#        output                              Append preprocessed source files to this list
#        [SOURCES file1 [file2]... ]         List of source files to append
#        [FYPP_ARGS arg1 [arg2]...]          Arguments passed to fypp
#        [FYPP_ARGS_EXCLUDE arg1 [arg2]...]  Arguments excluded from being passed to fypp; accepts bash-compatible regex
#        [DEPENDS dep1 [dep2]... ]           Dependencies before processing files
#
#    Notes:
#        The include flags and compile flags of targets with the DEPENDS argument
#        will be automatically deduced and added to the fypp command

function( fckit_preprocess_fypp_sources output )

  set( options NO_LINE_NUMBERING )
  set( single_value_args "" )
  set( multi_value_args SOURCES FYPP_ARGS FYPP_ARGS_EXCLUDE DEPENDS )
  cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}"  ${_FIRST_ARG} ${ARGN} )

  unset( outfiles )

  list( APPEND _PAR_FYPP_ARGS_EXCLUDE ${FCKIT_FYPP_ARGS_EXCLUDE})
  list( APPEND _PAR_FYPP_ARGS_EXCLUDE "-D[[:space:]]?.*=([0-9])+L" )
  list( APPEND _PAR_FYPP_ARGS_EXCLUDE "-D[[:space:]]?__.*" )
  list( JOIN   _PAR_FYPP_ARGS_EXCLUDE "," _PAR_FYPP_ARGS_EXCLUDE )

  foreach( filename ${_PAR_SOURCES} )

    get_filename_component( dir ${filename} DIRECTORY )
    get_filename_component( base ${filename} NAME_WE )
    set( outfile ${CMAKE_CURRENT_BINARY_DIR} )
    if( dir )
      set( outfile "${outfile}/${dir}" )
    endif()
    set( outfile "${outfile}/${base}.F90" )

    list( APPEND outfiles ${outfile} )

    unset(args)
    list( APPEND args -l 132 ) # Line length
    list( APPEND args -p )     # Create parent folder
    set( _enable_line_numbers TRUE )
    if( _PAR_NO_LINE_NUMBERING OR FYPP_NO_LINE_NUMBERING )
      set( _enable_line_numbers FALSE )
    endif()
    if( CMAKE_Fortran_COMPILER_ID MATCHES "Cray" )
      set( _enable_line_numbers FALSE )
      # Compiler errors occur (tested with cce/8.7.5 )
    endif()
    if( _enable_line_numbers )
      list( APPEND args -n )   # Create line numbering for compile errors
      if( CMAKE_Fortran_COMPILER_ID MATCHES "Intel" )
        list( APPEND args --line-marker-format=gfortran5 )
      endif()
      if( CMAKE_Fortran_COMPILER_ID MATCHES "NAG" )
        # workaround for line markers in continuation lines ( see e.g. https://github.com/ecmwf/atlas/pull/193 )
        list( APPEND args --line-numbering-mode=nocontlines )
      endif()
      # list( APPEND args -N nocontlines )  # workaround for line numbers in continuation lines
    endif()

    if( _PAR_FYPP_ARGS )
        set( args ${args} ${_PAR_FYPP_ARGS} )
    endif()

    foreach( target ${_PAR_DEPENDS} )
      fckit_target_append_fypp_args( args ${target} )
    endforeach()

    if( dir )
      set( short_outfile "${dir}/${base}.F90" )
    else()
      set( short_outfile "${base}.F90")
    endif()

    get_source_file_property( _depends ${filename} OBJECT_DEPENDS )

    unset( ${filename}_depends )
    if( _depends )
       set( ${filename}_depends ${_depends} )
    endif()

    add_custom_command(
      OUTPUT ${outfile}
      COMMAND ${CMAKE_COMMAND} -E env FCKIT_EVAL_ARGS_EXCLUDE="${_PAR_FYPP_ARGS_EXCLUDE}" ${FYPP} ${args} ${CMAKE_CURRENT_SOURCE_DIR}/${filename} ${outfile}
      DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${filename} ${_PAR_DEPENDS} ${${filename}_depends}
      COMMENT "[fypp] Preprocessor generating ${short_outfile}" )

    set_source_files_properties(${outfile} PROPERTIES GENERATED TRUE)

    ### Extra stuff required to add correct flags
    # ecbuild 3.2 compatible properties that need to be transferred from .fypp files to .F90
    foreach( _prop COMPILE_FLAGS
                   COMPILE_FLAGS_${CMAKE_BUILD_TYPE_CAPS}
                   COMPILE_OPTIONS
                   OVERRIDE_COMPILE_FLAGS
                   OVERRIDE_COMPILE_FLAGS_${CMAKE_BUILD_TYPE_CAPS} )
      get_source_file_property( ${filename}_${_prop} ${filename} ${_prop} )
      if( ${filename}_${_prop} )
        set_source_files_properties(${outfile} PROPERTIES ${_prop} ${${filename}_${_prop}} )
      endif()
    endforeach()

  endforeach()

  # Append to output and set in parent scope
  set(${output} ${${output}} ${outfiles} PARENT_SCOPE)


endfunction()

##############################################################################################


##############################################################################################
# fckit_target_preprocess_fypp( target
#                               [FYPP_ARGS arg1 [arg2]... ]
#                               [FYPP_ARGS_EXCLUDE arg1 [arg2]... ]
#                               [DEPENDS dep1 [dep2]... ] )
#    Purpose:
#        Preprocess source files in the target with the extensions
#        {.fypp, .fypp.F90, .F90.fypp}
#
#    Arguments:
#        target                               Preprocess all files from this target
#        [FYPP_ARGS arg1 [arg2]...]           Arguments passed to fypp
#        [FYPP_ARGS_EXCLUDE arg1 [arg2]... ]  Arguments excluded from being passed to fypp; accepts bash-compatible regex
#        [DEPENDS dep1 [dep2]... ]            Dependencies before processing files
#
#    Notes:
#        The include flags and compile flags of current target and targets
#        within the DEPENDS argument will be automatically deduced
#        and added to the fypp command

function( fckit_target_preprocess_fypp _PAR_TARGET )

  set( options NO_LINE_NUMBERING )
  set( single_value_args "" )
  set( multi_value_args FYPP_ARGS FYPP_ARGS_EXCLUDE DEPENDS )
  cmake_parse_arguments( _PAR "${options}" "${single_value_args}" "${multi_value_args}"  ${_FIRST_ARG} ${ARGN} )

  if( TARGET ${_PAR_TARGET} )

      get_target_property( _target_sources ${_PAR_TARGET} SOURCES )

      unset( sources_to_be_preprocessed )
      foreach( source ${_target_sources} )
        if( source MATCHES ".fypp.F90" )
          list( APPEND sources_to_be_preprocessed ${source} )
        elseif( source MATCHES ".F90.fypp" )
          list( APPEND sources_to_be_preprocessed ${source} )
        elseif( source MATCHES ".fypp" )
          list( APPEND sources_to_be_preprocessed ${source} )
        endif()
      endforeach()
      foreach( source ${sources_to_be_preprocessed} )
        set( source_files_properties ${source} PROPERTIES HEADER_FILE_ONLY TRUE )
      endforeach()

### BUG WORKAROUND (tested upto CMake 3.13.2)
#   Even though source files to be preprocessed with final extension .F90 have just been
#   declared as HEADER_FILE_ONLY, CMake still tries to compile these files.
#   This does not happen for files ending with other extensions ( .fypp )
      set( _create_fypp_target FALSE )
      foreach( source ${sources_to_be_preprocessed} )
        if( source MATCHES ".fypp.F90" )
          set( _create_fypp_target TRUE )
          list(FILTER _target_sources EXCLUDE REGEX ${source} )
        endif()
      endforeach()
      if( NOT TARGET ${_PAR_TARGET}_fypp AND _create_fypp_target )
          set_property( TARGET ${_PAR_TARGET} PROPERTY SOURCES ${_target_sources} )
          add_custom_target( ${_PAR_TARGET}_fypp SOURCES ${sources_to_be_preprocessed} )
      endif()
### END BUG WORKAROUND



      foreach( depends_property LINK_DEPENDS;MANUALLY_ADDED_DEPENDENCIES )
        get_target_property( target_depends ${_PAR_TARGET} ${depends_property} )
        if( target_depends )
          set( preprocessed_depends ${preprocessed_depends} ${target_depends} )
        endif()
      endforeach()

      fckit_target_append_fypp_args( args ${_PAR_TARGET} )

      if( _PAR_NO_LINE_NUMBERING )
          set( _NO_LINE_NUMBERING NO_LINE_NUMBERING )
      endif()

      fckit_preprocess_fypp_sources( preprocessed_sources
          SOURCES ${sources_to_be_preprocessed}
          ${_NO_LINE_NUMBERING}
          FYPP_ARGS ${_PAR_FYPP_ARGS} ${args}
          FYPP_ARGS_EXCLUDE ${_PAR_FYPP_ARGS_EXCLUDE}
          DEPENDS ${preprocessed_depends} ${_PAR_DEPENDS}
      )

      target_sources( ${_PAR_TARGET} PRIVATE ${preprocessed_sources} )

      ### Extra stuff required to add correct flags
      if( COMMAND ecbuild_target_flags )
        list( APPEND ${_PAR_TARGET}_fortran_srcs ${preprocessed_sources} )
        list( APPEND ${_PAR_TARGET}_Fortran_srcs ${preprocessed_sources} )
        ecbuild_target_flags( ${_PAR_TARGET} "" "" "")
          # Currently it is not possible to add flags that were added within
          # ecbuild_add_library( ... FFLAGS <FFLAGS CFLAGS <CFLAGS> CXXFLAGS <CXXFLAGS> )
          # until ecbuild exports these variables
          # Therefore 3 empty strings for these.
          # Luckily this is a very tiny use case
      endif()

### BUG WORKAROUND for CMake < 3.12
#   CMake seems to not add the "-fPIC -h PIC" flags for the Cray compiler when the target
#   has the POSITION_INDEPENDENT_CODE property set, so add it manually
    if( CMAKE_VERSION VERSION_LESS 3.12 )
      get_property( _target_pic TARGET ${_PAR_TARGET} PROPERTY POSITION_INDEPENDENT_CODE )
      if( _target_pic )
        if( CMAKE_Fortran_COMPILER_ID MATCHES "Cray" )
          foreach( _src ${preprocessed_sources} )
            set_source_files_properties( ${_src} COMPILE_FLAGS "-h PIC" )
          endforeach()
        endif()
      endif()
    endif()
  endif()
### END BUG WORKAROUND

endfunction()