From f54ff7ded683071d2dbaf746134035f1323814ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mario=20H=C3=BCttel?= Date: Sat, 15 Dec 2018 00:05:34 +0100 Subject: [PATCH] Add support for external shared object renderer --- CMakeLists.txt | 4 +-- command-line.c | 15 ++++++++-- command-line.h | 4 ++- external-renderer.c | 70 +++++++++++++++++++++++++++++++++++++++++++++ external-renderer.h | 58 +++++++++++++++++++++++++++++++++++++ main.c | 30 +++++++++++-------- 6 files changed, 164 insertions(+), 17 deletions(-) create mode 100644 external-renderer.c create mode 100644 external-renderer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index c087a1c..50ca59b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ aux_source_directory("gds-parser" PARSER_SOURCES) aux_source_directory("latex-output" LATEX_SOURCES) aux_source_directory("cairo-output" CAIRO_SOURCES) aux_source_directory("trigonometric" TRIG_SOURCES) -set(SOURCE "main.c" "layer-selector.c" "mapping-parser.c" "command-line.c" "main-window.c") +set(SOURCE "main.c" "layer-selector.c" "mapping-parser.c" "command-line.c" "main-window.c" "external-renderer.c") set(SOURCE ${SOURCE} @@ -36,6 +36,6 @@ add_compile_options(-Wall) add_executable(${PROJECT_NAME} ${SOURCE} ${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c) add_dependencies(${PROJECT_NAME} glib-resources) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/glade/resources.c PROPERTIES GENERATED 1) -target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m) +target_link_libraries(${PROJECT_NAME} ${GLIB_LDFLAGS} ${GTK3_LDFLAGS} ${CAIRO_LDFLAGS} m ${CMAKE_DL_LIBS}) install (TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/command-line.c b/command-line.c index dad5671..8f2d97d 100644 --- a/command-line.c +++ b/command-line.c @@ -34,6 +34,7 @@ #include "mapping-parser.h" #include "cairo-output/cairo-output.h" #include "latex-output/latex-output.h" +#include "external-renderer.h" /** * @brief Delete layer_info and free nem element. @@ -52,7 +53,7 @@ static void delete_layer_info_with_name(struct layer_info *info) void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex, char *layer_file, char *cell_name, double scale, gboolean pdf_layers, - gboolean pdf_standalone, gboolean svg, char *svg_name) + gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file) { GList *libs = NULL; FILE *tex_file; @@ -71,7 +72,7 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb struct gds_cell *toplevel_cell = NULL, *temp_cell; /* Check if parameters are valid */ - if (!gds_name || ! pdf_name || !tex_name || !layer_file || !cell_name) { + if (!gds_name || (!pdf_name && pdf) || (!tex_name && tex) || !layer_file || !cell_name) { printf("Probably missing argument. Check --help option\n"); return; } @@ -144,6 +145,16 @@ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gb fclose(tex_file); } + if (so_name && so_out_file) { + if (strlen(so_name) == 0 || strlen(so_out_file) == 0) + goto ret_clear_list; + + /* Render output using external renderer */ + printf("Invoking external renderer!\n"); + external_renderer_render_cell(toplevel_cell, layer_info_list, so_out_file, so_name); + printf("External renderer finished!\n"); + } + ret_clear_list: g_list_free_full(layer_info_list, (GDestroyNotify)delete_layer_info_with_name); diff --git a/command-line.h b/command-line.h index 9a15e8a..2908209 100644 --- a/command-line.h +++ b/command-line.h @@ -45,11 +45,13 @@ * @param pdf_layers TikZ creates OCG layers * @param pdf_standalone LaTeX document is standalone7 * @param svg Render to SVG file + * @param so_name Path to shared object of custom renderer + * @param so_out_file Output file path for custom renderer * @param svg_name SVG file name */ void command_line_convert_gds(char *gds_name, char *pdf_name, char *tex_name, gboolean pdf, gboolean tex, char *layer_file, char *cell_name, double scale, gboolean pdf_layers, - gboolean pdf_standalone, gboolean svg, char *svg_name); + gboolean pdf_standalone, gboolean svg, char *svg_name, char *so_name, char *so_out_file); #endif /* _COMMAND_LINE_H_ */ diff --git a/external-renderer.c b/external-renderer.c new file mode 100644 index 0000000..8b7dd90 --- /dev/null +++ b/external-renderer.c @@ -0,0 +1,70 @@ +/* + * GDSII-Converter + * Copyright (C) 2018 Mario Hüttel + * + * This file is part of GDSII-Converter. + * + * GDSII-Converter is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * GDSII-Converter is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDSII-Converter. If not, see . + */ + +/** + * @file external-renderer.c + * @brief This file implements the dynamic library loading for the external rendering feature + * @author Mario Hüttel + */ + +/** + * @addtogroup MainApplication + * @{ + */ + +#include "external-renderer.h" +#include +#include + +int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path) +{ + int (*so_render_func)(struct gds_cell *, GList *, char *) = NULL; + void *so_handle = NULL; + char *error_msg; + int ret = 0; + + /* Check parameter sanity */ + if (!output_file || !so_path || !toplevel_cell || !layer_info_list) { + return -3000; + } + + /* Load shared object */ + so_handle = dlopen(so_path, RTLD_LAZY); + if (!so_handle) { + printf("Could not load external library '%s'\nDetailed error is:\n%s\n", so_path, dlerror()); + return -2000; + } + + /* Load symbol from library */ + so_render_func = (int (*)(struct gds_cell *, GList *, char *))dlsym(so_handle, EXTERNAL_LIBRARY_FUNCTION); + if ((error_msg = dlerror()) != NULL) { + printf("Rendering function not found in library:\n%s\n", error_msg); + goto ret_close_so_handle; + } + + /* Execute */ + if (so_render_func) + so_render_func(toplevel_cell, layer_info_list, output_file); + +ret_close_so_handle: + dlclose(so_handle); + return ret; +} + +/** @} */ diff --git a/external-renderer.h b/external-renderer.h new file mode 100644 index 0000000..8c67d2a --- /dev/null +++ b/external-renderer.h @@ -0,0 +1,58 @@ +/* + * GDSII-Converter + * Copyright (C) 2018 Mario Hüttel + * + * This file is part of GDSII-Converter. + * + * GDSII-Converter is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * GDSII-Converter is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GDSII-Converter. If not, see . + */ + +/** + * @file command-line.c + * @brief Render according to command line parameters + * @author Mario Hüttel + */ + +/** + * @addtogroup MainApplication + * @{ + */ + +#ifndef _EXTERNAL_RENDERER_H_ +#define _EXTERNAL_RENDERER_H_ + +#include "gds-parser/gds-types.h" +#include + +/** + * @brief function name expected to be found in external library. + * @detail The function has to be defined as follows: + * @code + * int function_name(gds_cell *toplevel, GList *layer_info_list, char *output_file_name) + * @endcode + */ +#define EXTERNAL_LIBRARY_FUNCTION "render_cell_to_file" + +/** + * @brief external_renderer_render_cell + * @param toplevel_cell The toplevel cell to render + * @param layer_info_list The layer information. Contains #layer_info elements + * @param output_file Output file + * @param so_path Path to the shared object file containing #EXTERNAL_LIBRARY_FUNCTION + * @return 0 on success + */ +int external_renderer_render_cell(struct gds_cell *toplevel_cell, GList *layer_info_list, char *output_file, char *so_path); + +#endif /* _EXTERNAL_RENDERER_H_ */ + +/** @} */ diff --git a/main.c b/main.c index 6b308b8..5309c4d 100644 --- a/main.c +++ b/main.c @@ -22,6 +22,7 @@ #include #include "main-window.h" #include "command-line.h" +#include "external-renderer.h" struct application_data { GtkApplication *app; @@ -116,22 +117,26 @@ int main(int argc, char **argv) gchar *basename; gchar *pdfname = NULL, *texname = NULL, *mappingname = NULL, *cellname = NULL, *svgname = NULL; gboolean tikz = FALSE, pdf = FALSE, pdf_layers = FALSE, pdf_standalone = FALSE, svg = FALSE; + gchar *custom_library_path = NULL; + gchar *custom_library_file_name = NULL; int scale = 1000; int app_status; GOptionEntry entries[] = { - { "tikz", 't', 0, G_OPTION_ARG_NONE, &tikz, "Output TikZ code", NULL }, - { "pdf", 'p', 0, G_OPTION_ARG_NONE, &pdf, "Output PDF document", NULL }, - //{ "svg", 'S', 0, G_OPTION_ARG_NONE, &svg, "Output SVG image", NULL }, - { "scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by ", "" }, - { "tex-output", 'o', 0, G_OPTION_ARG_FILENAME, &texname, "Optional path for TeX file", "PATH" }, - { "pdf-output", 'O', 0, G_OPTION_ARG_FILENAME, &pdfname, "Optional path for PDF file", "PATH" }, - //{ "svg-output", 0, 0, G_OPTION_ARG_FILENAME, &svgname, "Optional path for PDF file", "PATH"}, - { "mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" }, - { "cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" }, - { "tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL }, - { "tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL }, + {"tikz", 't', 0, G_OPTION_ARG_NONE, &tikz, "Output TikZ code", NULL }, + {"pdf", 'p', 0, G_OPTION_ARG_NONE, &pdf, "Output PDF document", NULL }, + //{"svg", 'S', 0, G_OPTION_ARG_NONE, &svg, "Output SVG image", NULL }, + {"scale", 's', 0, G_OPTION_ARG_INT, &scale, "Divide output coordinates by ", "" }, + {"tex-output", 'o', 0, G_OPTION_ARG_FILENAME, &texname, "Optional path for TeX file", "PATH" }, + {"pdf-output", 'O', 0, G_OPTION_ARG_FILENAME, &pdfname, "Optional path for PDF file", "PATH" }, + //{"svg-output", 0, 0, G_OPTION_ARG_FILENAME, &svgname, "Optional path for PDF file", "PATH"}, + {"mapping", 'm', 0, G_OPTION_ARG_FILENAME, &mappingname, "Path for Layer Mapping File", "PATH" }, + {"cell", 'c', 0, G_OPTION_ARG_STRING, &cellname, "Cell to render", "NAME" }, + {"tex-standalone", 'a', 0, G_OPTION_ARG_NONE, &pdf_standalone, "Create standalone PDF", NULL }, + {"tex-layers", 'l', 0, G_OPTION_ARG_NONE, &pdf_layers, "Create PDF Layers (OCG)", NULL }, + {"custom-render-lib", 'P', 0, G_OPTION_ARG_FILENAME, &custom_library_path, "Path to a custom shared object, that implements the " EXTERNAL_LIBRARY_FUNCTION " function", "PATH"}, + {"external-lib-output", 'e', 0, G_OPTION_ARG_FILENAME, &custom_library_file_name, "Output path for external render library", "PATH"}, { NULL } }; @@ -171,7 +176,8 @@ int main(int argc, char **argv) command_line_convert_gds(gds_name, pdfname, texname, pdf, tikz, mappingname, cellname, (double)scale, - pdf_layers, pdf_standalone, svg, svgname); + pdf_layers, pdf_standalone, svg, svgname, + custom_library_path, custom_library_file_name); /* Clean up */ g_free(pdfname); g_free(texname);