1
1
! ># Store compiler commands in a `compile_commands.json` table
2
2
module fpm_compile_commands
3
- use fpm_toml, only: serializable_t, set_string, set_list, get_value, get_list, toml_table
3
+ use fpm_toml, only: serializable_t, set_string, set_list, get_value, get_list, toml_table, add_table
4
4
use fpm_strings, only: string_t, operator (==)
5
- use fpm_error, only: error_t
5
+ use fpm_error, only: error_t, syntax_error, fatal_error
6
+ use fpm_os, only: get_current_directory
7
+ use shlex_module, only: shlex_split = > split
6
8
implicit none
7
9
8
10
! > Definition of a build command
@@ -25,11 +27,14 @@ module fpm_compile_commands
25
27
26
28
type, extends(serializable_t) :: compile_command_table_t
27
29
28
-
29
30
type (compile_command_t), allocatable :: command(:)
30
31
31
32
contains
32
33
34
+ ! > Operation
35
+ procedure :: destroy = > cct_destroy
36
+ procedure :: register = > cct_register
37
+
33
38
! > Serialization interface
34
39
procedure :: serializable_is_same = > cct_is_same
35
40
procedure :: dump_to_toml = > cct_dump_toml
@@ -145,7 +150,79 @@ subroutine cct_dump_toml(self, table, error)
145
150
1 format (' compile_command_' ,i0)
146
151
147
152
end subroutine cct_dump_toml
153
+
154
+ ! > Cleanup a compile command table
155
+ elemental subroutine cct_destroy (self )
156
+
157
+ ! > Instance of the serializable object
158
+ class(compile_command_table_t), intent (inout ) :: self
159
+
160
+ if (allocated (self% command)) deallocate (self% command)
161
+
162
+ end subroutine cct_destroy
163
+
164
+ ! > Register a new compile command
165
+ subroutine cct_register (self , command , error )
148
166
167
+ ! > Instance of the serializable object
168
+ class(compile_command_table_t), intent (inout ) :: self
169
+
170
+ ! > Data structure
171
+ character (len=* ), intent (in ) :: command
172
+
173
+ ! > Error handling
174
+ type (error_t), allocatable , intent (out ) :: error
175
+
176
+ ! Local variables
177
+ type (compile_command_t) :: cmd
178
+ character (len= :), allocatable :: args(:), cwd, source_file
179
+ logical :: sh_success
180
+ integer :: i,n
181
+
182
+ ! Early check
183
+ if (len_trim (command) <= 0 ) then
184
+ call syntax_error(error, " compile_command_table_t trying to register an empty command" )
185
+ return
186
+ end if
187
+
188
+ ! Tokenize the input command into args(:)
189
+ args = shlex_split(command, join_spaced= .true. , keep_quotes= .true. , success= sh_success)
190
+ n = size (args)
191
+
192
+ if (n== 0 .or. .not. sh_success) then
193
+ call syntax_error(error, " compile_command_table_t failed tokenizing: <" // command// " >" )
194
+ return
195
+ end if
196
+
197
+ ! Get current working directory
198
+ call get_current_directory(cwd, error)
199
+ if (allocated (error)) return
200
+
201
+ ! Try to find the source file
202
+ allocate (character (len= 0 ) :: source_file)
203
+ find_source_file: do i = 1 , n-1
204
+ if (args(i) == " -c" ) then
205
+ source_file = args(i+1 )
206
+ exit find_source_file
207
+ end if
208
+ end do find_source_file
209
+
210
+ ! Fallback: use last argument if not found
211
+ if (len_trim (source_file)==0 ) source_file = args(n)
212
+
213
+ ! Fill in the compile_command_t
214
+ cmd = compile_command_t(directory = string_t(cwd), &
215
+ arguments = [(string_t(trim (args(i))), i= 1 ,n)], &
216
+ file = string_t(source_file))
217
+
218
+ if (allocated (self% command)) then
219
+ self% command = [self% command, cmd]
220
+ else
221
+ allocate (self% command(1 ), source= cmd)
222
+ end if
223
+
224
+ end subroutine cct_register
225
+
149
226
! > Read compile_command_table_t from toml table (no checks made at this stage)
150
227
subroutine cct_load_toml (self , table , error )
151
228
0 commit comments