9
9
10
10
import os
11
11
from pathlib import Path
12
- from typing import cast , List , Optional
12
+ from typing import cast , Dict , List , Optional
13
+ import warnings
13
14
14
15
from fab .tools .category import Category
15
16
from fab .tools .compiler import Compiler
@@ -51,6 +52,12 @@ def __init__(self, name: Optional[str] = None,
51
52
self ._compiler = compiler
52
53
self .flags .extend (os .getenv ("LDFLAGS" , "" ).split ())
53
54
55
+ # Maintain a set of flags for common libraries.
56
+ self ._lib_flags : Dict [str , List [str ]] = {}
57
+ # Allow flags to include before or after any library-specific flags.
58
+ self ._pre_lib_flags : List [str ] = []
59
+ self ._post_lib_flags : List [str ] = []
60
+
54
61
@property
55
62
def mpi (self ) -> bool :
56
63
''':returns: whether the linker supports MPI or not.'''
@@ -66,16 +73,71 @@ def check_available(self) -> bool:
66
73
67
74
return super ().check_available ()
68
75
76
+ def get_lib_flags (self , lib : str ) -> List [str ]:
77
+ '''Gets the standard flags for a standard library
78
+
79
+ :param lib: the library name
80
+
81
+ :returns: a list of flags
82
+
83
+ :raises RuntimeError: if lib is not recognised
84
+ '''
85
+ try :
86
+ return self ._lib_flags [lib ]
87
+ except KeyError :
88
+ raise RuntimeError (f"Unknown library name: '{ lib } '" )
89
+
90
+ def add_lib_flags (self , lib : str , flags : List [str ],
91
+ silent_replace : bool = False ):
92
+ '''Add a set of flags for a standard library
93
+
94
+ :param lib: the library name
95
+ :param flags: the flags to use with the library
96
+ :param silent_replace: if set, no warning will be printed when an
97
+ existing lib is overwritten.
98
+ '''
99
+ if lib in self ._lib_flags and not silent_replace :
100
+ warnings .warn (f"Replacing existing flags for library { lib } : "
101
+ f"'{ self ._lib_flags [lib ]} ' with "
102
+ f"'{ flags } '." )
103
+
104
+ # Make a copy to avoid modifying the caller's list
105
+ self ._lib_flags [lib ] = flags [:]
106
+
107
+ def remove_lib_flags (self , lib : str ):
108
+ '''Remove any flags configured for a standard library
109
+
110
+ :param lib: the library name
111
+ '''
112
+ try :
113
+ del self ._lib_flags [lib ]
114
+ except KeyError :
115
+ pass
116
+
117
+ def add_pre_lib_flags (self , flags : List [str ]):
118
+ '''Add a set of flags to use before any library-specific flags
119
+
120
+ :param flags: the flags to include
121
+ '''
122
+ self ._pre_lib_flags .extend (flags )
123
+
124
+ def add_post_lib_flags (self , flags : List [str ]):
125
+ '''Add a set of flags to use after any library-specific flags
126
+
127
+ :param flags: the flags to include
128
+ '''
129
+ self ._post_lib_flags .extend (flags )
130
+
69
131
def link (self , input_files : List [Path ], output_file : Path ,
70
132
openmp : bool ,
71
- add_libs : Optional [List [str ]] = None ) -> str :
133
+ libs : Optional [List [str ]] = None ) -> str :
72
134
'''Executes the linker with the specified input files,
73
135
creating `output_file`.
74
136
75
137
:param input_files: list of input files to link.
76
138
:param output_file: output file.
77
139
:param openm: whether OpenMP is requested or not.
78
- :param add_libs : additional linker flags .
140
+ :param libs : additional libraries to link with .
79
141
80
142
:returns: the stdout of the link command
81
143
'''
@@ -88,7 +150,12 @@ def link(self, input_files: List[Path], output_file: Path,
88
150
params = []
89
151
# TODO: why are the .o files sorted? That shouldn't matter
90
152
params .extend (sorted (map (str , input_files )))
91
- if add_libs :
92
- params += add_libs
153
+
154
+ if self ._pre_lib_flags :
155
+ params .extend (self ._pre_lib_flags )
156
+ for lib in (libs or []):
157
+ params .extend (self .get_lib_flags (lib ))
158
+ if self ._post_lib_flags :
159
+ params .extend (self ._post_lib_flags )
93
160
params .extend ([self ._output_flag , str (output_file )])
94
161
return self .run (params )
0 commit comments