1+ // ===---------------- AutoLoadDylibUtils.cpp ----------------===//
2+ //
3+ // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+ // See https://llvm.org/LICENSE.txt for license information.
5+ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+ //
7+ // ===----------------------------------------------------------------------===//
8+
9+ #include " llvm/ExecutionEngine/Orc/Shared/AutoLoadDylibUtils.h"
10+
11+ #include " llvm/Support/Debug.h"
12+ #include " llvm/Support/DynamicLibrary.h"
13+ #include " llvm/Support/ErrorHandling.h"
14+ #include " llvm/Support/FileSystem.h"
15+ #include " llvm/Support/Path.h"
16+
17+ namespace llvm {
18+ namespace orc {
19+
20+ #if defined(LLVM_ON_UNIX)
21+ const char *const kEnvDelim = " :" ;
22+ #elif defined(_WIN32)
23+ const char *const kEnvDelim = " ;" ;
24+ #else
25+ #error "Unknown platform (environmental delimiter)"
26+ #endif
27+
28+ #if defined(LLVM_ON_UNIX)
29+ bool Popen (const std::string &Cmd, llvm::SmallVectorImpl<char > &Buf, bool RdE) {
30+ if (FILE *PF = ::popen (RdE ? (Cmd + " 2>&1" ).c_str () : Cmd.c_str (), " r" )) {
31+ Buf.resize (0 );
32+ const size_t Chunk = Buf.capacity_in_bytes ();
33+ while (true ) {
34+ const size_t Len = Buf.size ();
35+ Buf.resize (Len + Chunk);
36+ const size_t R = ::fread (&Buf[Len], sizeof (char ), Chunk, PF);
37+ if (R < Chunk) {
38+ Buf.resize (Len + R);
39+ break ;
40+ }
41+ }
42+ ::pclose (PF);
43+ return !Buf.empty ();
44+ }
45+ return false ;
46+ }
47+ #endif
48+
49+ std::string NormalizePath (const std::string &Path) {
50+
51+ llvm::SmallString<256 > Buffer;
52+ std::error_code EC = llvm::sys::fs::real_path (Path, Buffer, true );
53+ if (EC)
54+ return std::string ();
55+ return std::string (Buffer.str ());
56+ }
57+
58+ static void LogNonExistantDirectory (StringRef Path) {
59+ #define DEBUG_TYPE " LogNonExistantDirectory"
60+ LLVM_DEBUG (dbgs () << " ignoring nonexistent directory \" " << Path << " \"\n " );
61+ #undef DEBUG_TYPE
62+ }
63+
64+ bool SplitPaths (StringRef PathStr, SmallVectorImpl<StringRef> &Paths,
65+ SplitMode Mode, StringRef Delim, bool Verbose) {
66+ #define DEBUG_TYPE " SplitPths"
67+
68+ assert (Delim.size () && " Splitting without a delimiter" );
69+
70+ #if defined(_WIN32)
71+ // Support using a ':' delimiter on Windows.
72+ const bool WindowsColon = Delim.equals (" :" );
73+ #endif
74+
75+ bool AllExisted = true ;
76+ for (std::pair<StringRef, StringRef> Split = PathStr.split (Delim);
77+ !Split.second .empty (); Split = PathStr.split (Delim)) {
78+
79+ if (!Split.first .empty ()) {
80+ bool Exists = sys::fs::is_directory (Split.first );
81+
82+ #if defined(_WIN32)
83+ // Because drive letters will have a colon we have to make sure the split
84+ // occurs at a colon not followed by a path separator.
85+ if (!Exists && WindowsColon && Split.first .size () == 1 ) {
86+ // Both clang and cl.exe support '\' and '/' path separators.
87+ if (Split.second .front () == ' \\ ' || Split.second .front () == ' /' ) {
88+ const std::pair<StringRef, StringRef> Tmp = Split.second .split (Delim);
89+ // Split.first = 'C', but we want 'C:', so Tmp.first.size()+2
90+ Split.first = StringRef (Split.first .data (), Tmp.first .size () + 2 );
91+ Split.second = Tmp.second ;
92+ Exists = sys::fs::is_directory (Split.first );
93+ }
94+ }
95+ #endif
96+
97+ AllExisted = AllExisted && Exists;
98+
99+ if (!Exists) {
100+ if (Mode == SplitMode::FailNonExistant) {
101+ if (Verbose) {
102+ // Exiting early, but still log all non-existant paths that we have
103+ LogNonExistantDirectory (Split.first );
104+ while (!Split.second .empty ()) {
105+ Split = PathStr.split (Delim);
106+ if (sys::fs::is_directory (Split.first )) {
107+ LLVM_DEBUG (dbgs () << " ignoring directory that exists \" "
108+ << Split.first << " \"\n " );
109+ } else
110+ LogNonExistantDirectory (Split.first );
111+ Split = Split.second .split (Delim);
112+ }
113+ if (!sys::fs::is_directory (Split.first ))
114+ LogNonExistantDirectory (Split.first );
115+ }
116+ return false ;
117+ } else if (Mode == SplitMode::AllowNonExistant)
118+ Paths.push_back (Split.first );
119+ else if (Verbose)
120+ LogNonExistantDirectory (Split.first );
121+ } else
122+ Paths.push_back (Split.first );
123+ }
124+
125+ PathStr = Split.second ;
126+ }
127+
128+ // Trim trailing sep in case of A:B:C:D:
129+ if (!PathStr.empty () && PathStr.ends_with (Delim))
130+ PathStr = PathStr.substr (0 , PathStr.size () - Delim.size ());
131+
132+ if (!PathStr.empty ()) {
133+ if (!sys::fs::is_directory (PathStr)) {
134+ AllExisted = false ;
135+ if (Mode == SplitMode::AllowNonExistant)
136+ Paths.push_back (PathStr);
137+ else if (Verbose)
138+ LogNonExistantDirectory (PathStr);
139+ } else
140+ Paths.push_back (PathStr);
141+ }
142+
143+ return AllExisted;
144+
145+ #undef DEBUG_TYPE
146+ }
147+
148+ bool GetSystemLibraryPaths (llvm::SmallVectorImpl<std::string> &Paths) {
149+ #if defined(__APPLE__) || defined(__CYGWIN__)
150+ Paths.push_back (" /usr/local/lib/" );
151+ Paths.push_back (" /usr/X11R6/lib/" );
152+ Paths.push_back (" /usr/lib/" );
153+ Paths.push_back (" /lib/" );
154+
155+ #ifndef __APPLE__
156+ Paths.push_back (" /lib/x86_64-linux-gnu/" );
157+ Paths.push_back (" /usr/local/lib64/" );
158+ Paths.push_back (" /usr/lib64/" );
159+ Paths.push_back (" /lib64/" );
160+ #endif
161+ #elif defined(LLVM_ON_UNIX)
162+ llvm::SmallString<1024 > Buf;
163+ Popen (" LD_DEBUG=libs LD_PRELOAD=DOESNOTEXIST ls" , Buf, true );
164+ const llvm::StringRef Result = Buf.str ();
165+
166+ const std::size_t NPos = std::string::npos;
167+ const std::size_t LD = Result.find (" (LD_LIBRARY_PATH)" );
168+ std::size_t From = Result.find (" search path=" , LD == NPos ? 0 : LD);
169+ if (From != NPos) {
170+ std::size_t To = Result.find (" (system search path)" , From);
171+ if (To != NPos) {
172+ From += 12 ;
173+ while (To > From && isspace (Result[To - 1 ]))
174+ --To;
175+ std::string SysPath = Result.substr (From, To - From).str ();
176+ SysPath.erase (std::remove_if (SysPath.begin (), SysPath.end (), ::isspace),
177+ SysPath.end ());
178+
179+ llvm::SmallVector<llvm::StringRef, 10 > CurPaths;
180+ SplitPaths (SysPath, CurPaths);
181+ for (const auto &Path : CurPaths)
182+ Paths.push_back (Path.str ());
183+ }
184+ }
185+ #endif
186+ return true ;
187+ }
188+
189+ } // namespace orc
190+ } // namespace llvm
0 commit comments