1 | // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "bin/extensions.h" |
6 | |
7 | #include <stdio.h> |
8 | |
9 | #include "bin/dartutils.h" |
10 | #include "bin/file.h" |
11 | #include "bin/platform.h" |
12 | #include "bin/utils.h" |
13 | #include "include/dart_api.h" |
14 | #include "platform/assert.h" |
15 | #include "platform/globals.h" |
16 | #include "platform/utils.h" |
17 | |
18 | namespace dart { |
19 | namespace bin { |
20 | |
21 | static char PathSeparator() { |
22 | const char* sep = File::PathSeparator(); |
23 | ASSERT(strlen(sep) == 1); |
24 | return sep[0]; |
25 | } |
26 | |
27 | void* Extensions::MakePathAndResolve(const char* dir, const char* name) { |
28 | // First try to find the library with a suffix specifying the architecture. |
29 | { |
30 | const char* path_components[] = { |
31 | dir, |
32 | Platform::LibraryPrefix(), |
33 | name, |
34 | "-" , |
35 | Platform::HostArchitecture(), // arm |
36 | "." , |
37 | Platform::LibraryExtension(), // so |
38 | NULL, |
39 | }; |
40 | const char* library_file = Concatenate(path_components); |
41 | void* library_handle = LoadExtensionLibrary(library_file); |
42 | if (library_handle != NULL) { |
43 | return library_handle; |
44 | } |
45 | } |
46 | |
47 | // Fall back on a library name without the suffix. |
48 | { |
49 | const char* path_components[] = { |
50 | dir, |
51 | Platform::LibraryPrefix(), |
52 | name, |
53 | "." , |
54 | Platform::LibraryExtension(), // so |
55 | NULL, |
56 | }; |
57 | const char* library_file = Concatenate(path_components); |
58 | return LoadExtensionLibrary(library_file); |
59 | } |
60 | } |
61 | |
62 | // IMPORTANT: In the absolute path case, do not extract the filename and search |
63 | // for that by passing it to LoadLibrary. That can lead to confusion in |
64 | // which the absolute path is wrong, and a different version of the library is |
65 | // loaded from the standard location. |
66 | void* Extensions::ResolveAbsPathExtension(const char* extension_path) { |
67 | const char* last_slash = strrchr(extension_path, PathSeparator()) + 1; |
68 | char* name = Utils::StrDup(last_slash); |
69 | char* dir = Utils::StrNDup(extension_path, last_slash - extension_path); |
70 | void* library_handle = MakePathAndResolve(dir, name); |
71 | free(dir); |
72 | free(name); |
73 | return library_handle; |
74 | } |
75 | |
76 | void* Extensions::ResolveExtension(const char* extension_directory, |
77 | const char* extension_name) { |
78 | // If the path following dart-ext is an absolute path, then only look for the |
79 | // library there. |
80 | if (File::IsAbsolutePath(extension_name)) { |
81 | return ResolveAbsPathExtension(extension_name); |
82 | } |
83 | |
84 | // If the path following dart-ext is just a file name, first look next to |
85 | // the importing Dart library. |
86 | void* library_handle = |
87 | MakePathAndResolve(extension_directory, extension_name); |
88 | if (library_handle != NULL) { |
89 | return library_handle; |
90 | } |
91 | |
92 | // Then pass the library name down to the platform. E.g. dlopen will do its |
93 | // own search in standard search locations. |
94 | return MakePathAndResolve("" , extension_name); |
95 | } |
96 | |
97 | Dart_Handle Extensions::LoadExtension(const char* extension_directory, |
98 | const char* extension_name, |
99 | Dart_Handle parent_library) { |
100 | void* library_handle = ResolveExtension(extension_directory, extension_name); |
101 | if (library_handle == NULL) { |
102 | return GetError(); |
103 | } |
104 | |
105 | const char* extension = extension_name; |
106 | if (File::IsAbsolutePath(extension_name)) { |
107 | extension = strrchr(extension_name, PathSeparator()) + 1; |
108 | } |
109 | |
110 | const char* strings[] = {extension, "_Init" , NULL}; |
111 | const char* init_function_name = Concatenate(strings); |
112 | void* init_function = ResolveSymbol(library_handle, init_function_name); |
113 | Dart_Handle result = GetError(); |
114 | if (Dart_IsError(result)) { |
115 | return result; |
116 | } |
117 | ASSERT(init_function != NULL); |
118 | typedef Dart_Handle (*InitFunctionType)(Dart_Handle import_map); |
119 | InitFunctionType fn = reinterpret_cast<InitFunctionType>(init_function); |
120 | return (*fn)(parent_library); |
121 | } |
122 | |
123 | // Concatenates a NULL terminated array of strings. |
124 | // The returned string is scope allocated. |
125 | const char* Extensions::Concatenate(const char** strings) { |
126 | int size = 1; // null termination. |
127 | for (int i = 0; strings[i] != NULL; i++) { |
128 | size += strlen(strings[i]); |
129 | } |
130 | char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(size)); |
131 | int index = 0; |
132 | for (int i = 0; strings[i] != NULL; i++) { |
133 | index += snprintf(result + index, size - index, "%s" , strings[i]); |
134 | } |
135 | ASSERT(index == size - 1); |
136 | ASSERT(result[size - 1] == '\0'); |
137 | return result; |
138 | } |
139 | |
140 | } // namespace bin |
141 | } // namespace dart |
142 | |