GDS-Render v1.2.1
external-renderer.c
Go to the documentation of this file.
1/*
2 * GDSII-Converter
3 * Copyright (C) 2018 Mario Hüttel <mario.huettel@gmx.net>
4 *
5 * This file is part of GDSII-Converter.
6 *
7 * GDSII-Converter is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * GDSII-Converter is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GDSII-Converter. If not, see <http://www.gnu.org/licenses/>.
18 */
19
31#include <dlfcn.h>
32#include <stdio.h>
33#include <sys/wait.h>
34#include <glib/gi18n.h>
35
37#include <gds-render/version.h>
38
39#define FORCE_FORK 0U
42 GdsOutputRenderer parent;
45};
46
47enum {
51};
52
53G_DEFINE_TYPE(ExternalRenderer, external_renderer, GDS_RENDER_TYPE_OUTPUT_RENDERER)
54
55
65static int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list,
66 const char *output_file, double scale, const char *so_path, const char *params)
67{
68 int (*so_render_func)(struct gds_cell *, GList *, const char *, double) = NULL;
69 int (*so_init_func)(const char *, const char *) = NULL;
70 void *so_handle = NULL;
71 char *error_msg;
72 int forking_req;
73 int ret = 0;
74 pid_t fork_pid = 0;
75 int forked_status;
76
77 if (!so_path) {
78 fprintf(stderr, _("Path to shared object not set!\n"));
79 return -3000;
80 }
81
82 /* Check parameter sanity */
83 if (!output_file || !toplevel_cell || !layer_info_list)
84 return -3000;
85
86 /* Load shared object */
87 so_handle = dlopen(so_path, RTLD_LAZY);
88 if (!so_handle) {
89 fprintf(stderr, _("Could not load external library '%s'\nDetailed error is:\n%s\n"), so_path, dlerror());
90 return -2000;
91 }
92
93 /* Load rendering symbol from library */
94 so_render_func = (int (*)(struct gds_cell *, GList *, const char *, double))
95 dlsym(so_handle, xstr(EXTERNAL_LIBRARY_RENDER_FUNCTION));
96 error_msg = dlerror();
97 if (error_msg != NULL) {
98 fprintf(stderr, _("Rendering function not found in library:\n%s\n"), error_msg);
99 goto ret_close_so_handle;
100 }
101
102 /* Load the init function */
103 so_init_func = (int (*)(const char *, const char *))dlsym(so_handle, xstr(EXTERNAL_LIBRARY_INIT_FUNCTION));
104 error_msg = dlerror();
105 if (error_msg != NULL) {
106 fprintf(stderr, _("Init function not found in library:\n%s\n"), error_msg);
107 goto ret_close_so_handle;
108 }
109
110 /* Check if forking is requested */
111 if (dlsym(so_handle, xstr(EXTERNAL_LIBRARY_FORK_REQUEST)))
112 forking_req = 1;
113 else if (FORCE_FORK)
114 forking_req = 1;
115 else
116 forking_req = 0;
117
118 /* Execute */
119
120 g_message(_("Calling external renderer."));
121
122 if (forking_req)
123 fork_pid = fork();
124 if (fork_pid != 0)
125 goto end_forked;
126
127 ret = so_init_func(params, _app_version_string);
128 if (!ret)
129 ret = so_render_func(toplevel_cell, layer_info_list, output_file, scale);
130
131 /* If we are in a separate process, terminate here */
132 if (forking_req)
133 exit(ret);
134
135 /* The forked paths end here */
136end_forked:
137 if (forking_req) {
138 waitpid(fork_pid, &forked_status, 0);
139 ret = WEXITSTATUS(forked_status);
140 }
141
142 g_message(_("External renderer finished."));
143
144ret_close_so_handle:
145 dlclose(so_handle);
146 return ret;
147}
148
149static int external_renderer_render_output(GdsOutputRenderer *renderer,
150 struct gds_cell *cell,
151 double scale)
152{
153 ExternalRenderer *ext_renderer = GDS_RENDER_EXTERNAL_RENDERER(renderer);
154 LayerSettings *settings;
155 GList *layer_infos = NULL;
156 const char *output_file;
157 int ret;
158
159 output_file = gds_output_renderer_get_output_file(renderer);
161
162 /* Set layer info list. In case of failure it remains NULL */
163 if (settings)
164 layer_infos = layer_settings_get_layer_info_list(settings);
165
166 ret = external_renderer_render_cell(cell, layer_infos, output_file, scale, ext_renderer->shared_object_path,
167 ext_renderer->cli_param_string);
168 if (settings)
169 g_object_unref(settings);
170
171 return ret;
172}
173
174static void external_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
175{
176 ExternalRenderer *self;
177
178 self = GDS_RENDER_EXTERNAL_RENDERER(obj);
179
180 switch (property_id) {
181 case PROP_SO_PATH:
182 g_value_set_string(value, self->shared_object_path);
183 break;
185 g_value_set_string(value, self->cli_param_string);
186 break;
187 default:
188 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
189 break;
190 }
191}
192
193static void external_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
194{
195 ExternalRenderer *self;
196
197 self = GDS_RENDER_EXTERNAL_RENDERER(obj);
198
199 switch (property_id) {
200 case PROP_SO_PATH:
201 if (self->shared_object_path)
202 g_free(self->shared_object_path);
203 self->shared_object_path = g_value_dup_string(value);
204 break;
206 if (self->cli_param_string)
207 g_free(self->cli_param_string);
208 self->cli_param_string = g_value_dup_string(value);
209 break;
210 default:
211 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, property_id, pspec);
212 break;
213 }
214}
215
216static void external_renderer_dispose(GObject *self_obj)
217{
218 ExternalRenderer *self;
219
220 self = GDS_RENDER_EXTERNAL_RENDERER(self_obj);
221
222 if (self->shared_object_path) {
223 g_free(self->shared_object_path);
224 self->shared_object_path = NULL;
225 }
226
227 G_OBJECT_CLASS(external_renderer_parent_class)->dispose(self_obj);
228}
229
230static GParamSpec *external_renderer_properties[N_PROPERTIES] = {NULL};
231
232static void external_renderer_class_init(ExternalRendererClass *klass)
233{
234 GdsOutputRendererClass *inherited_parent_class;
235 GObjectClass *oclass;
236
237 inherited_parent_class = GDS_RENDER_OUTPUT_RENDERER_CLASS(klass);
238 oclass = G_OBJECT_CLASS(klass);
239
240 /* Override virtual function */
241 inherited_parent_class->render_output = external_renderer_render_output;
242
243 /* Setup Gobject callbacks */
244 oclass->set_property = external_renderer_set_property;
245 oclass->get_property = external_renderer_get_property;
246 oclass->dispose = external_renderer_dispose;
247
248 /* Setup properties */
250 g_param_spec_string(N_("shared-object-path"),
251 N_("Shared object file path"),
252 N_("Path to the shared object to search rendering function in."),
253 NULL,
254 G_PARAM_READWRITE);
256 g_param_spec_string(N_("param-string"),
257 N_("Shared object renderer parameter string"),
258 N_("Command line arguments passed to the external shared object renderer"),
259 NULL,
260 G_PARAM_READWRITE);
261 g_object_class_install_properties(oclass, N_PROPERTIES, external_renderer_properties);
262}
263
264static void external_renderer_init(ExternalRenderer *self)
265{
266 self->shared_object_path = NULL;
267 self->cli_param_string = NULL;
268}
269
270ExternalRenderer *external_renderer_new()
271{
272 return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, NULL);
273}
274
275ExternalRenderer *external_renderer_new_with_so_and_param(const char *so_path, const char *param_string)
276{
277 return g_object_new(GDS_RENDER_TYPE_EXTERNAL_RENDERER, N_("shared-object-path"), so_path,
278 N_("param-string"), param_string, NULL);
279}
280
#define xstr(a)
Render according to command line parameters.
static void external_renderer_set_property(GObject *obj, guint property_id, const GValue *value, GParamSpec *pspec)
#define GDS_RENDER_TYPE_EXTERNAL_RENDERER
#define EXTERNAL_LIBRARY_FORK_REQUEST
Global integer specified by an external renderer to signal, that the init and render functions shall ...
static void external_renderer_get_property(GObject *obj, guint property_id, GValue *value, GParamSpec *pspec)
static GParamSpec * external_renderer_properties[N_PROPERTIES]
static void external_renderer_init(ExternalRenderer *self)
static int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, const char *output_file, double scale, const char *so_path, const char *params)
Execute render function in shared object to render the supplied cell.
static void external_renderer_class_init(ExternalRendererClass *klass)
static int external_renderer_render_output(GdsOutputRenderer *renderer, struct gds_cell *cell, double scale)
ExternalRenderer * external_renderer_new()
Create new ExternalRenderer object.
ExternalRenderer * external_renderer_new_with_so_and_param(const char *so_path, const char *param_string)
Create new ExternalRenderer object with specified shared object path.
#define FORCE_FORK
if != 0, then forking is forced regardless of the shared object's settings
static void external_renderer_dispose(GObject *self_obj)
@ N_PROPERTIES
Shared object renderer parameter string from CLI.
@ PROP_PARAM_STRING
@ PROP_SO_PATH
Shared object path property.
const char * gds_output_renderer_get_output_file(GdsOutputRenderer *renderer)
Convenience function for getting the "output-file" property.
LayerSettings * gds_output_renderer_get_and_ref_layer_settings(GdsOutputRenderer *renderer)
Get layer settings.
#define GDS_RENDER_TYPE_OUTPUT_RENDERER
int EXPORTED_FUNC_DECL() EXTERNAL_LIBRARY_RENDER_FUNCTION(struct gds_cell *toplevel, GList *layer_info_list, const char *output_file_name, double scale)
Definition: plugin-main.c:34
int EXPORTED_FUNC_DECL() EXTERNAL_LIBRARY_INIT_FUNCTION(const char *params, const char *version)
Definition: plugin-main.c:43
const char * _app_version_string
This string holds the Git Based Version Number of the app.
Definition: version.c:32
GList * layer_settings_get_layer_info_list(LayerSettings *settings)
Get a GList with layer_info structs.
GdsOutputRenderer parent
A Cell inside a gds_library.
Definition: gds-types.h:122