v2 / vlib / dl / loader / loader.v
150 lines · 125 sloc · 3.91 KB · 008aaad99981918c51194d7aaaaaccb4c258f244
Raw
1@[has_globals]
2module loader
3
4import dl
5import os
6
7const dl_no_path_issue_msg = 'no paths to dynamic library'
8const dl_open_issue_msg = 'could not open dynamic library'
9const dl_sym_issue_msg = 'could not get optional symbol from dynamic library'
10const dl_close_issue_msg = 'could not close dynamic library'
11const dl_register_issue_msg = 'could not register dynamic library loader'
12
13pub const dl_no_path_issue_code = 1
14pub const dl_open_issue_code = 1
15pub const dl_sym_issue_code = 2
16pub const dl_close_issue_code = 3
17pub const dl_register_issue_code = 4
18
19pub const dl_no_path_issue_err = error_with_code(dl_no_path_issue_msg, dl_no_path_issue_code)
20pub const dl_open_issue_err = error_with_code(dl_open_issue_msg, dl_open_issue_code)
21pub const dl_sym_issue_err = error_with_code(dl_sym_issue_msg, dl_sym_issue_code)
22pub const dl_close_issue_err = error_with_code(dl_close_issue_msg, dl_close_issue_code)
23pub const dl_register_issue_err = error_with_code(dl_register_issue_msg, dl_register_issue_code)
24
25__global (
26 registered_dl_loaders map[string]&DynamicLibLoader
27)
28
29fn register_dl_loader(dl_loader &DynamicLibLoader) ! {
30 if dl_loader.key in registered_dl_loaders {
31 return dl_register_issue_err
32 }
33 registered_dl_loaders[dl_loader.key] = dl_loader
34}
35
36// registered_dl_loader_keys returns the keys of registered DynamicLibLoader.
37pub fn registered_dl_loader_keys() []string {
38 return registered_dl_loaders.keys()
39}
40
41// DynamicLibLoader is a wrapper around dlopen, dlsym and dlclose.
42@[heap]
43pub struct DynamicLibLoader {
44pub:
45 key string
46 flags int = dl.rtld_lazy
47 paths []string
48mut:
49 handle voidptr
50 sym_map map[string]voidptr
51}
52
53// DynamicLibLoaderConfig is a configuration for DynamicLibLoader.
54@[params]
55pub struct DynamicLibLoaderConfig {
56pub:
57 // flags is the flags for dlopen.
58 flags int = dl.rtld_lazy
59 // key is the key to register the DynamicLibLoader.
60 key string
61 // env_path is the environment variable name that contains the path to the dynamic library.
62 env_path string
63 // paths is the list of paths to the dynamic library.
64 paths []string
65}
66
67// new_dynamic_lib_loader returns a new DynamicLibLoader.
68fn new_dynamic_lib_loader(conf DynamicLibLoaderConfig) !&DynamicLibLoader {
69 mut paths := []string{}
70
71 if conf.env_path != '' {
72 if env_path := os.getenv_opt(conf.env_path) {
73 paths << env_path.split(os.path_delimiter)
74 }
75 }
76
77 paths << conf.paths
78
79 if paths.len == 0 {
80 return dl_no_path_issue_err
81 }
82
83 mut dl_loader := &DynamicLibLoader{
84 key: conf.key
85 flags: conf.flags
86 paths: paths
87 }
88
89 register_dl_loader(dl_loader)!
90 return dl_loader
91}
92
93// get_or_create_dynamic_lib_loader returns a DynamicLibLoader.
94// If the DynamicLibLoader is not registered, it creates a new DynamicLibLoader.
95pub fn get_or_create_dynamic_lib_loader(conf DynamicLibLoaderConfig) !&DynamicLibLoader {
96 if dl_loader := registered_dl_loaders[conf.key] {
97 return dl_loader
98 }
99 return new_dynamic_lib_loader(conf)
100}
101
102// load loads the dynamic library.
103pub fn (mut dl_loader DynamicLibLoader) open() !voidptr {
104 if !isnil(dl_loader.handle) {
105 return dl_loader.handle
106 }
107
108 for path in dl_loader.paths {
109 if handle := dl.open_opt(path, dl_loader.flags) {
110 dl_loader.handle = handle
111 return handle
112 }
113 }
114
115 return dl_open_issue_err
116}
117
118// close closes the dynamic library.
119pub fn (mut dl_loader DynamicLibLoader) close() ! {
120 if !isnil(dl_loader.handle) {
121 if dl.close(dl_loader.handle) {
122 dl_loader.handle = unsafe { nil }
123 return
124 }
125 }
126
127 return dl_close_issue_err
128}
129
130// get_sym gets a symbol from the dynamic library.
131pub fn (mut dl_loader DynamicLibLoader) get_sym(name string) !voidptr {
132 if sym := dl_loader.sym_map[name] {
133 return sym
134 }
135
136 handle := dl_loader.open()!
137 if sym := dl.sym_opt(handle, name) {
138 dl_loader.sym_map[name] = sym
139 return sym
140 }
141
142 dl_loader.close()!
143 return dl_sym_issue_err
144}
145
146// unregister unregisters the DynamicLibLoader.
147pub fn (mut dl_loader DynamicLibLoader) unregister() {
148 dl_loader.close() or {}
149 registered_dl_loaders.delete(dl_loader.key)
150}
151