3 # Copyright The SCons Foundation
5 # Permission is hereby granted, free of charge, to any person obtaining
6 # a copy of this software and associated documentation files (the
7 # "Software"), to deal in the Software without restriction, including
8 # without limitation the rights to use, copy, modify, merge, publish,
9 # distribute, sublicense, and/or sell copies of the Software, and to
10 # permit persons to whom the Software is furnished to do so, subject to
11 # the following conditions:
13 # The above copyright notice and this permission notice shall be included
14 # in all copies or substantial portions of the Software.
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
17 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
18 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Common link/shared library logic
30 from SCons
.Tool
.DCommon
import isD
31 from SCons
.Util
import is_List
33 issued_mixed_link_warning
= False
36 def StringizeLibSymlinks(symlinks
):
37 """Converts list with pairs of nodes to list with pairs of node paths
38 (strings). Used mainly for debugging."""
41 return [(k
.get_path(), v
.get_path()) for k
, v
in symlinks
]
42 except (TypeError, ValueError):
48 def EmitLibSymlinks(env
, symlinks
, libnode
, **kw
) -> None:
49 """Used by emitters to handle (shared/versioned) library symlinks"""
52 # nodes involved in process... all symlinks + library
53 nodes
= list(set([x
for x
, y
in symlinks
] + [libnode
]))
55 clean_targets
= kw
.get('clean_targets', [])
56 if not is_List(clean_targets
):
57 clean_targets
= [clean_targets
]
59 for link
, linktgt
in symlinks
:
60 env
.SideEffect(link
, linktgt
)
62 print("EmitLibSymlinks: SideEffect(%r,%r)" % (link
.get_path(), linktgt
.get_path()))
63 clean_list
= [x
for x
in nodes
if x
!= linktgt
]
64 env
.Clean(list(set([linktgt
] + clean_targets
)), clean_list
)
66 print("EmitLibSymlinks: Clean(%r,%r)" % (linktgt
.get_path(), [x
.get_path() for x
in clean_list
]))
69 def CreateLibSymlinks(env
, symlinks
) -> int:
70 """Physically creates symlinks. The symlinks argument must be a list in
71 form [ (link, linktarget), ... ], where link and linktarget are SCons
76 for link
, linktgt
in symlinks
:
77 linktgt
= link
.get_dir().rel_path(linktgt
)
78 link
= link
.get_path()
80 print("CreateLibSymlinks: preparing to add symlink %r -> %r" % (link
, linktgt
))
81 # Delete the (previously created) symlink if exists. Let only symlinks
82 # to be deleted to prevent accidental deletion of source files...
83 if env
.fs
.islink(link
):
86 print("CreateLibSymlinks: removed old symlink %r" % link
)
87 # If a file or directory exists with the same name as link, an OSError
88 # will be thrown, which should be enough, I think.
89 env
.fs
.symlink(linktgt
, link
)
91 print("CreateLibSymlinks: add symlink %r -> %r" % (link
, linktgt
))
95 def LibSymlinksActionFunction(target
, source
, env
) -> int:
97 symlinks
= getattr(getattr(tgt
, 'attributes', None), 'shliblinks', None)
99 CreateLibSymlinks(env
, symlinks
)
103 def LibSymlinksStrFun(target
, source
, env
, *args
):
106 symlinks
= getattr(getattr(tgt
, 'attributes', None), 'shliblinks', None)
108 if cmd
is None: cmd
= ""
110 cmd
+= "Create symlinks for: %r\n " % tgt
.get_path()
112 linkstr
= '\n '.join(["%r->%r" % (k
, v
) for k
, v
in StringizeLibSymlinks(symlinks
)])
113 except (KeyError, ValueError):
116 cmd
+= "%s" % linkstr
120 def _call_env_subst(env
, string
, *args
, **kw
):
122 for k
in ('raw', 'target', 'source', 'conv', 'executor'):
127 return env
.subst(string
, *args
, **kw2
)
130 def smart_link(source
, target
, env
, for_signature
) -> str:
131 import SCons
.Tool
.cxx
132 import SCons
.Tool
.FortranCommon
134 has_cplusplus
= SCons
.Tool
.cxx
.iscplusplus(source
)
135 has_fortran
= SCons
.Tool
.FortranCommon
.isfortran(env
, source
)
136 has_d
= isD(env
, source
)
137 if has_cplusplus
and has_fortran
and not has_d
:
138 global issued_mixed_link_warning
139 if not issued_mixed_link_warning
:
141 "Using $CXX to link Fortran and C++ code together.\n"
142 " This may generate a buggy executable if the '%s'\n"
143 " compiler does not know how to deal with Fortran runtimes."
146 SCons
.Warnings
.FortranCxxMixWarning
, msg
% env
.subst('$CXX')
148 issued_mixed_link_warning
= True
151 env
['LINKCOM'] = env
['DLINKCOM']
152 env
['SHLINKCOM'] = env
['SHDLINKCOM']
161 def lib_emitter(target
, source
, env
, **kw
):
164 print(f
"_lib_emitter: target[0]={target[0].get_path()!r}")
166 if SCons
.Util
.is_String(tgt
):
168 tgt
.attributes
.shared
= True
170 return target
, source