From d9815a6837f1e06def0641da285863f87729683f Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Fri, 20 Jan 2017 13:53:56 -0200 Subject: CMake: move eina binaries to single dir, add helper macros. For one-source directories, be smart and just define SOURCES to that, will reduce the number of too-simplistic CMakeLists.txt in our tree. This also fixes problems with libraries, they should be private, not public. So specify both kinds as different variables. --- cmake/helpers/EflMacros.cmake | 85 +++-- src/Makefile_Eina.am | 18 +- src/bin/eina/eina_btlog.c | 525 ------------------------------- src/bin/eina/eina_btlog/eina_btlog.c | 525 +++++++++++++++++++++++++++++++ src/bin/eina/eina_modinfo.c | 57 ---- src/bin/eina/eina_modinfo/eina_modinfo.c | 57 ++++ src/lib/eina/CMakeLists.txt | 6 +- 7 files changed, 659 insertions(+), 614 deletions(-) delete mode 100644 src/bin/eina/eina_btlog.c create mode 100644 src/bin/eina/eina_btlog/eina_btlog.c delete mode 100644 src/bin/eina/eina_modinfo.c create mode 100644 src/bin/eina/eina_modinfo/eina_modinfo.c diff --git a/cmake/helpers/EflMacros.cmake b/cmake/helpers/EflMacros.cmake index 4665a03a80..1c2c752107 100644 --- a/cmake/helpers/EflMacros.cmake +++ b/cmake/helpers/EflMacros.cmake @@ -137,6 +137,49 @@ function(EFL_FILES_TO_ABSOLUTE _var _srcdir _bindir) set(${_var} "${_lst}" PARENT_SCOPE) endfunction() +# _EFL_INCLUDE_OR_DETECT(Name Source_Dir) +# +# Internal macro that will include(${Source_Dir}/CMakeLists.txt) if +# that exists, otherwise will check if there is a single source file, +# in that case it will automatically define SOURCES to that (including +# extras such as headers and .eo) +# +# Name is only used to print out messages when it's auto-detected. +macro(_EFL_INCLUDE_OR_DETECT _name _srcdir) + if(EXISTS ${_srcdir}/CMakeLists.txt) + include(${_srcdir}/CMakeLists.txt) + else() + # doc says it's not recommended because it can't know if more files + # were added, but we're doing this explicitly to handle one file. + file(GLOB _autodetect_files RELATIVE ${_srcdir} + ${_srcdir}/*.c + ${_srcdir}/*.h + ${_srcdir}/*.hh + ${_srcdir}/*.cxx + ${_srcdir}/*.cpp + ${_srcdir}/*.eo + ) + list(LENGTH _autodetect_files _autodetect_files_count) + if(_autodetect_files_count GREATER 1) + message(WARNING "${_name}: ${_srcdir} contains no CMakeLists.txt and contains more than one source file. Don't know what to do, then ignored.") + elseif(_autodetect_files_count EQUAL 1) + file(GLOB SOURCES RELATIVE ${_srcdir} + ${_srcdir}/*.c + ${_srcdir}/*.h + ${_srcdir}/*.hh + ${_srcdir}/*.cxx + ${_srcdir}/*.cpp + ${_srcdir}/*.eo + ) + message(STATUS "${_name} auto-detected as: ${SOURCES}") + else() + message(STATUS "${_name} contains no auto-detectable sources.") + endif() + unset(_autodetect_files_count) + unset(_autodetect_files) + endif() +endmacro() + # _EFL_LIB_PROCESS_MODULES_INTERNAL() # # Internal function to process modules of current EFL_LIB() @@ -149,8 +192,6 @@ function(_EFL_LIB_PROCESS_MODULES_INTERNAL) if(IS_DIRECTORY ${EFL_MODULES_SOURCE_DIR}/${module}) set(EFL_MODULE_SCOPE ${module}) - include(${EFL_MODULES_SOURCE_DIR}/${module}/CMakeLists.txt OPTIONAL) - file(GLOB submodules RELATIVE ${EFL_MODULES_SOURCE_DIR}/${EFL_MODULE_SCOPE} ${EFL_MODULES_SOURCE_DIR}/${EFL_MODULE_SCOPE}/*) foreach(submodule ${submodules}) if(IS_DIRECTORY ${EFL_MODULES_SOURCE_DIR}/${EFL_MODULE_SCOPE}/${submodule}) @@ -227,7 +268,8 @@ endfunction() # - LIBRARY_TYPE: SHARED or STATIC, defaults to SHARED # - OBJECT_DEPENDS: say this object depends on other files (ie: includes) # - DEPENDENCIES: results in add_dependencies() -# - LIBRARIES: results in target_link_libraries() +# - LIBRARIES: results in target_link_libraries(LINK_PRIVATE) +# - PUBLIC_LIBRARIES: results in target_link_libraries(LINK_PUBLIC) # - DEFINITIONS: target_compile_definitions() # # Defines the following variables that can be used within the included files: @@ -291,6 +333,7 @@ function(EFL_LIB _target) set(OBJECT_DEPENDS) set(DEPENDENCIES) set(LIBRARIES) + set(PUBLIC_LIBRARIES) set(DEFINITIONS) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config/${_target}.cmake OPTIONAL) @@ -317,7 +360,10 @@ function(EFL_LIB _target) endif() if(LIBRARIES) - target_link_libraries(${_target} ${LIBRARIES}) + target_link_libraries(${_target} LINK_PRIVATE ${LIBRARIES}) + endif() + if(PUBLIC_LIBRARIES) + target_link_libraries(${_target} LINK_PRIVATE ${PUBLIC_LIBRARIES}) endif() target_include_directories(${_target} PUBLIC @@ -364,10 +410,9 @@ function(EFL_LIB _target) unset(OBJECT_DEPENDS) unset(DEPENDENCIES) unset(LIBRARIES) + unset(PUBLIC_LIBRARIES) unset(DEFINITIONS) - include(${EFL_BIN_SOURCE_DIR}/CMakeLists.txt OPTIONAL) - _EFL_LIB_PROCESS_BINS_INTERNAL() _EFL_LIB_PROCESS_MODULES_INTERNAL() _EFL_LIB_PROCESS_TESTS_INTERNAL() @@ -420,7 +465,7 @@ function(EFL_BIN _binname) set(_bintarget "${_binname}") endif() - include(${_binsrcdir}/CMakeLists.txt) + _EFL_INCLUDE_OR_DETECT("Binary ${_bintarget}" ${_binsrcdir}) if(NOT SOURCES) message(WARNING "${_binsrcdir}/CMakeLists.txt defines no SOURCES") @@ -452,7 +497,7 @@ function(EFL_BIN _binname) target_include_directories(${_bintarget} SYSTEM PRIVATE ${SYSTEM_INCLUDE_DIRECTORIES}) endif() - target_link_libraries(${_bintarget} + target_link_libraries(${_bintarget} LINK_PRIVATE ${EFL_LIB_CURRENT} ${LIBRARIES}) @@ -517,7 +562,7 @@ function(EFL_TEST _testname) set(_testtarget "${EFL_LIB_CURRENT}-test-${_testname}") endif() - include(${_testsrcdir}/CMakeLists.txt) + _EFL_INCLUDE_OR_DETECT("Test ${_testtarget}" ${_testsrcdir}) if(NOT SOURCES) message(WARNING "${_testsrcdir}/CMakeLists.txt defines no SOURCES") @@ -548,7 +593,7 @@ function(EFL_TEST _testname) target_include_directories(${_testtarget} SYSTEM PRIVATE ${SYSTEM_INCLUDE_DIRECTORIES} ${CHECK_INCLUDE_DIRS}) - target_link_libraries(${_testtarget} + target_link_libraries(${_testtarget} LINK_PRIVATE ${EFL_LIB_CURRENT} ${LIBRARIES} ${CHECK_LIBRARIES}) @@ -597,9 +642,13 @@ function(EFL_MODULE _modname) if(EFL_MODULE_SCOPE) set(_modsrcdir ${EFL_MODULES_SOURCE_DIR}/${EFL_MODULE_SCOPE}/${_modname}) set(_modoutdir lib/${EFL_LIB_CURRENT}/modules/${EFL_MODULE_SCOPE}/${_modname}/v-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}) + set(_modbindir ${EFL_MODULES_BINARY_DIR}/${EFL_MODULE_SCOPE}/${_modname}) + set(_modtarget ${EFL_LIB_CURRENT}-module-${EFL_MODULE_SCOPE}-${_modname}) else() set(_modsrcdir ${EFL_MODULES_SOURCE_DIR}/${_modname}) set(_modoutdir lib/${EFL_LIB_CURRENT}/modules/${_modname}/v-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}) + set(_modbindir ${EFL_MODULES_BINARY_DIR}/${_modname}) + set(_modtarget ${EFL_LIB_CURRENT}-module-${_modname}) endif() set(SOURCES) @@ -611,7 +660,7 @@ function(EFL_MODULE _modname) set(MODULE_TYPE "ON") set(INSTALL_DIR ${_modoutdir}) - include(${_modsrcdir}/CMakeLists.txt) + _EFL_INCLUDE_OR_DETECT("Module ${_modtarget}" ${_modsrcdir}) if(NOT SOURCES) message(WARNING "${_modsrcdir}/CMakeLists.txt defines no SOURCES") @@ -621,14 +670,6 @@ function(EFL_MODULE _modname) message(WARNING "${_modsrcdir}/CMakeLists.txt should not define PUBLIC_HEADERS, it's not to be installed.") endif() - if(EFL_MODULE_SCOPE) - set(_modbindir ${EFL_MODULES_BINARY_DIR}/${EFL_MODULE_SCOPE}/${_modname}) - set(_modtarget ${EFL_LIB_CURRENT}-module-${EFL_MODULE_SCOPE}-${_modname}) - else() - set(_modbindir ${EFL_MODULES_BINARY_DIR}/${_modname}) - set(_modtarget ${EFL_LIB_CURRENT}-module-${_modname}) - endif() - if("${MODULE_TYPE}" STREQUAL "OFF") return() elseif("${MODULE_TYPE}" STREQUAL "STATIC") @@ -652,7 +693,7 @@ function(EFL_MODULE _modname) ${INCLUDE_DIRECTORIES}) target_include_directories(${_modtarget} SYSTEM PUBLIC ${SYSTEM_INCLUDE_DIRECTORIES}) - target_link_libraries(${_modtarget} ${LIBRARIES}) + target_link_libraries(${_modtarget} LINK_PRIVATE ${LIBRARIES}) target_compile_definitions(${_modtarget} PRIVATE ${DEFINITIONS}) @@ -662,7 +703,7 @@ function(EFL_MODULE _modname) RUNTIME_OUTPUT_DIRECTORY "${_modoutdir}") if("${MODULE_TYPE}" STREQUAL "STATIC") - target_link_libraries(${EFL_LIB_CURRENT} ${_modtarget}) + target_link_libraries(${EFL_LIB_CURRENT} LINK_PRIVATE ${_modtarget}) target_include_directories(${_modtarget} PRIVATE ${EFL_LIB_SOURCE_DIR} ${EFL_LIB_BINARY_DIR}) @@ -671,7 +712,7 @@ function(EFL_MODULE _modname) LIST_APPEND_GLOBAL(${EFL_LIB_CURRENT}_STATIC_MODULES ${_modtarget}) else() - target_link_libraries(${_modtarget} ${EFL_LIB_CURRENT}) + target_link_libraries(${_modtarget} LINK_PRIVATE ${EFL_LIB_CURRENT}) LIST_APPEND_GLOBAL(${EFL_LIB_CURRENT}_MODULES ${_modtarget}) if(INSTALL_DIR) install(TARGETS ${_modtarget} LIBRARY DESTINATION "${INSTALL_DIR}") diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am index ae3d94ba2f..1b6a08e760 100644 --- a/src/Makefile_Eina.am +++ b/src/Makefile_Eina.am @@ -263,28 +263,28 @@ lib_eina_libeina_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ ### Binaries -bin_PROGRAMS += bin/eina/eina_btlog +bin_PROGRAMS += bin/eina/eina_btlog/eina_btlog -bin_eina_eina_btlog_SOURCES = bin/eina/eina_btlog.c -bin_eina_eina_btlog_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +bin_eina_eina_btlog_eina_btlog_SOURCES = bin/eina/eina_btlog/eina_btlog.c +bin_eina_eina_btlog_eina_btlog_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/eina\" \ @EINA_CFLAGS@ -bin_eina_eina_btlog_LDADD = @USE_EINA_LIBS@ -bin_eina_eina_btlog_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ +bin_eina_eina_btlog_eina_btlog_LDADD = @USE_EINA_LIBS@ +bin_eina_eina_btlog_eina_btlog_DEPENDENCIES = @USE_EINA_INTERNAL_LIBS@ -bin_PROGRAMS += bin/eina/eina_modinfo +bin_PROGRAMS += bin/eina/eina_modinfo/eina_modinfo -bin_eina_eina_modinfo_SOURCES = bin/eina/eina_modinfo.c -bin_eina_eina_modinfo_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +bin_eina_eina_modinfo_eina_modinfo_SOURCES = bin/eina/eina_modinfo.c +bin_eina_eina_modinfo_eina_modinfo_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -DPACKAGE_BIN_DIR=\"$(bindir)\" \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/eina\" \ @EINA_CFLAGS@ -bin_eina_eina_modinfo_LDADD = @USE_EINA_LIBS@ +bin_eina_eina_modinfo_eina_modinfo_LDADD = @USE_EINA_LIBS@ ### Script diff --git a/src/bin/eina/eina_btlog.c b/src/bin/eina/eina_btlog.c deleted file mode 100644 index db8eb9332d..0000000000 --- a/src/bin/eina/eina_btlog.c +++ /dev/null @@ -1,525 +0,0 @@ -/* EINA - EFL data type library - * Copyright (C) 2015 Carsten Haitzler - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; - * if not, see . - */ - -#include -#include -#include -#include - -// right now this is quick and dirty and may have some parsing ... frailty, -// so don't put malicious data through it... :) but cat in eina bt's through -// this to get a nicely clean and readable bt with filenames of binaries, -// shared objects, source files, and line numbers. even nicely colored and -// columnated. this is more the start of a bunch of debug tools for efl to make -// it easier to identify issues. -// -// how to use: -// -// cat mybacktrace.txt | eina_btlog -// -// (or just run it and copy & paste in on stdin - what i do mostly, and out -// pops a nice backtrace, hit ctrl+d to end) - -#if defined (__MacOSX__) || (defined (__MACH__) && defined (__APPLE__)) -# define ATOS_COMPATIBLE -#endif - -typedef struct _Bt Bt; - -struct _Bt -{ - char *bin_dir; - char *bin_name; - char *file_dir; - char *file_name; - char *func_name; - char *comment; - int line; -}; - -typedef Eina_Bool (*Translate_Func)(const char *prog, - const char *bin_dir, - const char *bin_name, - unsigned long long addr, - char **file_dir, - char **file_name, - char **func_name, - int *file_line); - -typedef struct _Translation_Desc Translation_Desc; - -struct _Translation_Desc -{ - const char *name; - const char *test; - Translate_Func func; - const char *prog; -}; - -static Translate_Func _translate = NULL; -static const char *_prog = NULL; -static Eina_Bool color = EINA_TRUE; -static Eina_Bool show_comments = EINA_TRUE; -static Eina_Bool show_compact = EINA_FALSE; - -static void -path_split(const char *path, char **dir, char **file) -{ - const char *p; - - if (!path) - { - *dir = NULL; - *file = NULL; - return; - } - p = strrchr(path, '/'); - if (!p) - { - *dir = NULL; - *file = strdup(path); - return; - } - *dir = malloc(p - path + 1); - if (!*dir) - { - *dir = NULL; - *file = NULL; - return; - } - strncpy(*dir, path, p - path); - (*dir)[p - path] = 0; - *file = strdup(p + 1); -} - -static Eina_Bool -_addr2line(const char *prog, const char *bin_dir, const char *bin_name, unsigned long long addr, - char **file_dir, char **file_name, char **func_name, int *file_line) -{ - char buf[4096], func[4096], *f1 = NULL, *f2 = NULL; - Eina_Bool ok = EINA_FALSE; - int line; - FILE *p; - - snprintf(buf, sizeof(buf), "%s -f -e %s/%s -C -a 0x%llx", - prog, bin_dir, bin_name, addr); - p = popen(buf, "r"); - if (!p) return EINA_FALSE; - if ((fscanf(p, "%4095s\n", buf) == 1) && - (fscanf(p, "%4095s\n", func) == 1)) - { - if (fscanf(p, "%[^:]:%i\n", buf, &line) == 2) - { - path_split(buf, &(f1), &(f2)); - if ((!f1) || (!f2)) - { - free(f1); - free(f2); - pclose(p); - return EINA_FALSE; - } - } - else - { - f1 = strdup("??"); - f2 = strdup("??"); - } - *file_dir = f1; - *file_name = f2; - *func_name = strdup(func); - *file_line = line; - ok = EINA_TRUE; - } - pclose(p); - return ok; -} - -#ifdef ATOS_COMPATIBLE -static Eina_Bool -_atos(const char *prog, const char *bin_dir, const char *bin_name, unsigned long long addr, - char **file_dir, char **file_name, char **func_name, int *file_line) -{ - char buf[4096]; - FILE *p = NULL; - char *f1 = NULL, *s; - Eina_Bool ret = EINA_FALSE; - unsigned int count = 0, len; - Eina_Bool func_done = EINA_FALSE; - unsigned int spaces = 0, func_space_count; - - // Example of what we want to parse - // $ atos -o /usr/local/lib/libevas.1.dylib 0xa82d - // evas_object_clip_recalc (in libevas.1.dylib) (evas_inline.x:353) - // - // WARNING! Sometimes: - // tlv_load_notification (in libdyld.dylib) + 382 - // - // WARNING! Objective-C methods: - // -[EcoreCocoaWindow windowDidResize:] (in libecore_cocoa.1.dylib) (ecore_cocoa_window.m:97) - - snprintf(buf, sizeof(buf), "%s -o %s/%s 0x%llx", prog, bin_dir, bin_name, addr); - p = popen(buf, "r"); - if (!p) goto end; - - s = fgets(buf, sizeof(buf), p); - if (!s) goto end; - - /* Default value, used as a fallback when cannot be determined */ - *file_line = -1; - - if ((*s == '-') || (*s == '+')) /* objc methods... will contain an extra space */ - func_space_count = 2; - else - func_space_count = 1; - - do - { - if (*s == ' ') spaces++; - - if ((spaces == func_space_count) && (func_done == EINA_FALSE)) - { - *s = '\0'; - *func_name = strndup(buf, (int)(s - &(buf[0]))); - func_done = EINA_TRUE; - } - else if (*s == '(') - { - count++; - if ((count == 2) && (f1 == NULL)) - { - f1 = s + 1; /* skip the leading '(' */ - } - } - else if ((*s == ':') && (func_done == EINA_TRUE)) - { - *s = '\0'; - *file_name = strndup(f1, (int)(s - f1)); - s++; - len = strlen(s); - s[len - 1] = '\0'; /* Remove the closing parenthesis */ - *file_line = atoi(s); - break; /* Done */ - } - } - while (*(++s) != '\0'); - - /* Cannot be determined */ - *file_dir = strdup("??"); - - if (!*func_name) *func_name = strdup("??"); - if (!*file_name) *file_name = strdup("??"); - - ret = EINA_TRUE; -end: - if (p) pclose(p); - return ret; -} -#endif - -static const char * -bt_input_translate(const char *line, char **comment) -{ - static char local[PATH_MAX + sizeof(" 0x1234567890123456789 0x1234567890123456789\n")]; - const char *addrstart, *addrend, *filestart, *fileend, *basestart, *baseend; - - /* new bt format is more human readable, but needs some cleanup before we bt_append() - * - * Example: - * ERR<23314>:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00000005c7c291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x5c5c000) - * ERR<23314>:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00000004e409aa: libeo_dbg.so+0x99aa (in src/lib/eo/.libs/libeo_dbg.so 0x4e37000) - */ - *comment = NULL; - - addrstart = strstr(line, "0x"); - if (!addrstart) return NULL; - - addrend = strchr(addrstart, ':'); - if (!addrend) return NULL; - - filestart = strstr(addrend, "(in "); - if (!filestart) return NULL; - - filestart += strlen("(in "); - basestart = strstr(filestart, " 0x"); - if (!basestart) return NULL; - fileend = basestart; - basestart += strlen(" "); - baseend = strchr(basestart, ')'); - if (!baseend) return NULL; - - snprintf(local, sizeof(local), "%.*s %.*s %.*s\n", - (int)(fileend - filestart), filestart, - (int)(addrend - addrstart), addrstart, - (int)(baseend - basestart), basestart); - *comment = strndup(line, addrstart - line); - return local; -} - -static Eina_List * -bt_append(Eina_List *btl, const char *btline) -{ - Bt *bt = calloc(1, sizeof(Bt)); - if (!bt) return btl; - const char *translation; - char *comment = NULL; - char *bin = strdup(btline); - unsigned long long offset = 0, base = 0; - - translation = bt_input_translate(btline, &comment); - if (translation) - btline = translation; - - // parse: - // /usr/local/lib/libeina.so.1 0x1ec88 - // /usr/local/lib/libelementary.so.1 0x10f695 - // /usr/local/lib/libeo.so.1 0xa474 - // /usr/local/lib/libelementary.so.1 0x139bd6 - // /usr/local/bin/elementary_test 0x8196d - // /usr/local/bin/elementary_test 0x81b6a - if (sscanf(btline, "%s %llx %llx", bin, &offset, &base) == 3) - { - path_split(bin, &(bt->bin_dir), &(bt->bin_name)); - if (!bt->bin_dir) bt->bin_dir = strdup(""); - if (!bt->bin_name) bt->bin_name = strdup(""); - if (!_translate(_prog, bt->bin_dir, bt->bin_name, offset - base, - &(bt->file_dir), &(bt->file_name), - &(bt->func_name), &(bt->line))) - { - if (!_translate(_prog, bt->bin_dir, bt->bin_name, offset, - &(bt->file_dir), &(bt->file_name), - &(bt->func_name), &(bt->line))) - { - bt->file_dir = strdup(""); - bt->file_name = strdup(""); - bt->func_name = strdup(""); - } - } - bt->comment = comment; - btl = eina_list_append(btl, bt); - } - else - { - free(comment); - bt->comment = strdup(btline); - btl = eina_list_append(btl, bt); - } - free(bin); - - return btl; -} - -static Eina_Bool -_translation_function_detect(const Translation_Desc *desc) -{ - const Translation_Desc *d = desc; - FILE *p; - int ret; - - while ((d->name != NULL) && (d->func != NULL) && (d->test != NULL)) - { - p = popen(d->test, "r"); - if (p) - { - ret = pclose(p); - if (ret == 0) - { - _translate = d->func; - _prog = d->prog; - break; - } - } - d++; - } - - return (_translate == NULL) ? EINA_FALSE : EINA_TRUE; -} - -int -main(int argc, char **argv) -{ - Eina_List *btl = NULL, *l; - char buf[4096]; - Bt *bt; - int cols[6] = { 0 }, len, i; - const char *func_color = ""; - const char *dir_color = ""; - const char *sep_color = ""; - const char *file_color = ""; - const char *line_color = ""; - const char *reset_color = ""; - const Translation_Desc desc[] = { -#ifdef ATOS_COMPATIBLE - { /* Mac OS X */ - .name = "atos", - .test = "atos --help &> /dev/null", - .func = _atos, - .prog = "atos" - }, - { /* Mac OS X */ - .name = "atos (old)", - .test = "xcrun atos --help &> /dev/null", - .func = _atos, - .prog = "xcrun atos" - }, -#endif - { /* GNU binutils */ - .name = "addr2line", - .test = "addr2line --help &> /dev/null", - .func = _addr2line, - .prog = "addr2line" - }, - { /* For imported GNU binutils */ - .name = "GNU addr2line", - .test = "gaddr2line --help &> /dev/null", - .func = _addr2line, - .prog = "addr2line" - }, - { NULL, NULL, NULL } /* Sentinel */ - }; - - eina_init(); - - for (i = 1; i < argc; i++) - { - if (!strcmp(argv[i], "-h")) - { - printf("Usage: eina_btlog [-n]\n" - " -n Do not use color escape codes\n" - " -C Do not show comments (non-bt fragments)\n" - " -c Show compact output format\n" - "\n" - "Provide addresses logged from EFL applications to stdin.\n" - "Example:\n\n" - "\tcat log.txt | eina_btlog\n" - "\n"); - eina_shutdown(); - return 0; - } - else if (!strcmp(argv[i], "-n")) color = EINA_FALSE; - else if (!strcmp(argv[i], "-C")) show_comments = EINA_FALSE; - else if (!strcmp(argv[i], "-c")) show_compact = EINA_TRUE; - } - - if (color) - { - func_color = EINA_COLOR_GREEN; - dir_color = EINA_COLOR_BLUE; - sep_color = EINA_COLOR_CYAN; - file_color = EINA_COLOR_WHITE; - line_color = EINA_COLOR_YELLOW; - reset_color = EINA_COLOR_RESET; - } - - if (!_translation_function_detect(desc)) - { - EINA_LOG_CRIT("Fail to determine a program to translate backtrace " - "into human-readable text"); - return 1; - } - - repeat: - while (fgets(buf, sizeof(buf) - 1, stdin)) - { - btl = bt_append(btl, buf); - if (show_compact) goto do_show; - bt = eina_list_last_data_get(btl); - if (bt && !bt->bin_dir) break; /* flush once first non-bt is found */ - } - - /* compute columns for expanded display */ - for (i = 0; i < 6; i++) cols[i] = 0; - EINA_LIST_FOREACH(btl, l, bt) - { - if (!bt->bin_dir) continue; - len = strlen(bt->bin_dir); - if (len > cols[0]) cols[0] = len; - len = strlen(bt->bin_name); - if (len > cols[1]) cols[1] = len; - - len = strlen(bt->file_dir); - if (len > cols[2]) cols[2] = len; - len = strlen(bt->file_name); - if (len > cols[3]) cols[3] = len; - - snprintf(buf, sizeof(buf), "%i", bt->line); - len = strlen(buf); - if (len > cols[4]) cols[4] = len; - - len = strlen(bt->func_name); - if (len > cols[5]) cols[5] = len; - } - - do_show: - EINA_LIST_FOREACH(btl, l, bt) - { - if (bt->comment && show_comments) - fputs(bt->comment, stdout); - if (!bt->bin_dir) continue; - - if (show_compact) - { - printf("%s%s%s (in %s%s%s:%s%d%s)\n", - func_color, bt->func_name, reset_color, - file_color, bt->file_name, reset_color, - line_color, bt->line, reset_color); - fflush(stdout); - continue; - } - - printf(" " - "%s%*s%s/%s%-*s%s" /* bin info */ - "| " - "%s%*s%s/%s%-*s%s" /* file info */ - ": " - "%s%*i%s" /* line info */ - " @ " - "%s%s%s()%s\n", /* func info */ - /* bin info */ - dir_color, cols[0], bt->bin_dir, sep_color, - file_color, cols[1], bt->bin_name, - reset_color, - /* file info */ - dir_color, cols[2], bt->file_dir, sep_color, - file_color, cols[3], bt->file_name, - reset_color, - /* line info */ - line_color, cols[4], bt->line, - reset_color, - /* func info */ - func_color, bt->func_name, - sep_color, - reset_color); - } - fflush(stdout); - EINA_LIST_FREE(btl, bt) - { - free(bt->bin_dir); - free(bt->bin_name); - free(bt->file_dir); - free(bt->file_name); - free(bt->func_name); - free(bt->comment); - free(bt); - } - /* if not EOF, then we just flushed due non-bt line, try again */ - if (!feof(stdin)) goto repeat; - - eina_shutdown(); - - return 0; -} diff --git a/src/bin/eina/eina_btlog/eina_btlog.c b/src/bin/eina/eina_btlog/eina_btlog.c new file mode 100644 index 0000000000..db8eb9332d --- /dev/null +++ b/src/bin/eina/eina_btlog/eina_btlog.c @@ -0,0 +1,525 @@ +/* EINA - EFL data type library + * Copyright (C) 2015 Carsten Haitzler + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + */ + +#include +#include +#include +#include + +// right now this is quick and dirty and may have some parsing ... frailty, +// so don't put malicious data through it... :) but cat in eina bt's through +// this to get a nicely clean and readable bt with filenames of binaries, +// shared objects, source files, and line numbers. even nicely colored and +// columnated. this is more the start of a bunch of debug tools for efl to make +// it easier to identify issues. +// +// how to use: +// +// cat mybacktrace.txt | eina_btlog +// +// (or just run it and copy & paste in on stdin - what i do mostly, and out +// pops a nice backtrace, hit ctrl+d to end) + +#if defined (__MacOSX__) || (defined (__MACH__) && defined (__APPLE__)) +# define ATOS_COMPATIBLE +#endif + +typedef struct _Bt Bt; + +struct _Bt +{ + char *bin_dir; + char *bin_name; + char *file_dir; + char *file_name; + char *func_name; + char *comment; + int line; +}; + +typedef Eina_Bool (*Translate_Func)(const char *prog, + const char *bin_dir, + const char *bin_name, + unsigned long long addr, + char **file_dir, + char **file_name, + char **func_name, + int *file_line); + +typedef struct _Translation_Desc Translation_Desc; + +struct _Translation_Desc +{ + const char *name; + const char *test; + Translate_Func func; + const char *prog; +}; + +static Translate_Func _translate = NULL; +static const char *_prog = NULL; +static Eina_Bool color = EINA_TRUE; +static Eina_Bool show_comments = EINA_TRUE; +static Eina_Bool show_compact = EINA_FALSE; + +static void +path_split(const char *path, char **dir, char **file) +{ + const char *p; + + if (!path) + { + *dir = NULL; + *file = NULL; + return; + } + p = strrchr(path, '/'); + if (!p) + { + *dir = NULL; + *file = strdup(path); + return; + } + *dir = malloc(p - path + 1); + if (!*dir) + { + *dir = NULL; + *file = NULL; + return; + } + strncpy(*dir, path, p - path); + (*dir)[p - path] = 0; + *file = strdup(p + 1); +} + +static Eina_Bool +_addr2line(const char *prog, const char *bin_dir, const char *bin_name, unsigned long long addr, + char **file_dir, char **file_name, char **func_name, int *file_line) +{ + char buf[4096], func[4096], *f1 = NULL, *f2 = NULL; + Eina_Bool ok = EINA_FALSE; + int line; + FILE *p; + + snprintf(buf, sizeof(buf), "%s -f -e %s/%s -C -a 0x%llx", + prog, bin_dir, bin_name, addr); + p = popen(buf, "r"); + if (!p) return EINA_FALSE; + if ((fscanf(p, "%4095s\n", buf) == 1) && + (fscanf(p, "%4095s\n", func) == 1)) + { + if (fscanf(p, "%[^:]:%i\n", buf, &line) == 2) + { + path_split(buf, &(f1), &(f2)); + if ((!f1) || (!f2)) + { + free(f1); + free(f2); + pclose(p); + return EINA_FALSE; + } + } + else + { + f1 = strdup("??"); + f2 = strdup("??"); + } + *file_dir = f1; + *file_name = f2; + *func_name = strdup(func); + *file_line = line; + ok = EINA_TRUE; + } + pclose(p); + return ok; +} + +#ifdef ATOS_COMPATIBLE +static Eina_Bool +_atos(const char *prog, const char *bin_dir, const char *bin_name, unsigned long long addr, + char **file_dir, char **file_name, char **func_name, int *file_line) +{ + char buf[4096]; + FILE *p = NULL; + char *f1 = NULL, *s; + Eina_Bool ret = EINA_FALSE; + unsigned int count = 0, len; + Eina_Bool func_done = EINA_FALSE; + unsigned int spaces = 0, func_space_count; + + // Example of what we want to parse + // $ atos -o /usr/local/lib/libevas.1.dylib 0xa82d + // evas_object_clip_recalc (in libevas.1.dylib) (evas_inline.x:353) + // + // WARNING! Sometimes: + // tlv_load_notification (in libdyld.dylib) + 382 + // + // WARNING! Objective-C methods: + // -[EcoreCocoaWindow windowDidResize:] (in libecore_cocoa.1.dylib) (ecore_cocoa_window.m:97) + + snprintf(buf, sizeof(buf), "%s -o %s/%s 0x%llx", prog, bin_dir, bin_name, addr); + p = popen(buf, "r"); + if (!p) goto end; + + s = fgets(buf, sizeof(buf), p); + if (!s) goto end; + + /* Default value, used as a fallback when cannot be determined */ + *file_line = -1; + + if ((*s == '-') || (*s == '+')) /* objc methods... will contain an extra space */ + func_space_count = 2; + else + func_space_count = 1; + + do + { + if (*s == ' ') spaces++; + + if ((spaces == func_space_count) && (func_done == EINA_FALSE)) + { + *s = '\0'; + *func_name = strndup(buf, (int)(s - &(buf[0]))); + func_done = EINA_TRUE; + } + else if (*s == '(') + { + count++; + if ((count == 2) && (f1 == NULL)) + { + f1 = s + 1; /* skip the leading '(' */ + } + } + else if ((*s == ':') && (func_done == EINA_TRUE)) + { + *s = '\0'; + *file_name = strndup(f1, (int)(s - f1)); + s++; + len = strlen(s); + s[len - 1] = '\0'; /* Remove the closing parenthesis */ + *file_line = atoi(s); + break; /* Done */ + } + } + while (*(++s) != '\0'); + + /* Cannot be determined */ + *file_dir = strdup("??"); + + if (!*func_name) *func_name = strdup("??"); + if (!*file_name) *file_name = strdup("??"); + + ret = EINA_TRUE; +end: + if (p) pclose(p); + return ret; +} +#endif + +static const char * +bt_input_translate(const char *line, char **comment) +{ + static char local[PATH_MAX + sizeof(" 0x1234567890123456789 0x1234567890123456789\n")]; + const char *addrstart, *addrend, *filestart, *fileend, *basestart, *baseend; + + /* new bt format is more human readable, but needs some cleanup before we bt_append() + * + * Example: + * ERR<23314>:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00000005c7c291: __libc_start_main+0xf1 (in /usr/lib/libc.so.6 0x5c5c000) + * ERR<23314>:eo_lifecycle ../src/lib/eo/efl_object.eo.c:78 efl_del() 0x00000004e409aa: libeo_dbg.so+0x99aa (in src/lib/eo/.libs/libeo_dbg.so 0x4e37000) + */ + *comment = NULL; + + addrstart = strstr(line, "0x"); + if (!addrstart) return NULL; + + addrend = strchr(addrstart, ':'); + if (!addrend) return NULL; + + filestart = strstr(addrend, "(in "); + if (!filestart) return NULL; + + filestart += strlen("(in "); + basestart = strstr(filestart, " 0x"); + if (!basestart) return NULL; + fileend = basestart; + basestart += strlen(" "); + baseend = strchr(basestart, ')'); + if (!baseend) return NULL; + + snprintf(local, sizeof(local), "%.*s %.*s %.*s\n", + (int)(fileend - filestart), filestart, + (int)(addrend - addrstart), addrstart, + (int)(baseend - basestart), basestart); + *comment = strndup(line, addrstart - line); + return local; +} + +static Eina_List * +bt_append(Eina_List *btl, const char *btline) +{ + Bt *bt = calloc(1, sizeof(Bt)); + if (!bt) return btl; + const char *translation; + char *comment = NULL; + char *bin = strdup(btline); + unsigned long long offset = 0, base = 0; + + translation = bt_input_translate(btline, &comment); + if (translation) + btline = translation; + + // parse: + // /usr/local/lib/libeina.so.1 0x1ec88 + // /usr/local/lib/libelementary.so.1 0x10f695 + // /usr/local/lib/libeo.so.1 0xa474 + // /usr/local/lib/libelementary.so.1 0x139bd6 + // /usr/local/bin/elementary_test 0x8196d + // /usr/local/bin/elementary_test 0x81b6a + if (sscanf(btline, "%s %llx %llx", bin, &offset, &base) == 3) + { + path_split(bin, &(bt->bin_dir), &(bt->bin_name)); + if (!bt->bin_dir) bt->bin_dir = strdup(""); + if (!bt->bin_name) bt->bin_name = strdup(""); + if (!_translate(_prog, bt->bin_dir, bt->bin_name, offset - base, + &(bt->file_dir), &(bt->file_name), + &(bt->func_name), &(bt->line))) + { + if (!_translate(_prog, bt->bin_dir, bt->bin_name, offset, + &(bt->file_dir), &(bt->file_name), + &(bt->func_name), &(bt->line))) + { + bt->file_dir = strdup(""); + bt->file_name = strdup(""); + bt->func_name = strdup(""); + } + } + bt->comment = comment; + btl = eina_list_append(btl, bt); + } + else + { + free(comment); + bt->comment = strdup(btline); + btl = eina_list_append(btl, bt); + } + free(bin); + + return btl; +} + +static Eina_Bool +_translation_function_detect(const Translation_Desc *desc) +{ + const Translation_Desc *d = desc; + FILE *p; + int ret; + + while ((d->name != NULL) && (d->func != NULL) && (d->test != NULL)) + { + p = popen(d->test, "r"); + if (p) + { + ret = pclose(p); + if (ret == 0) + { + _translate = d->func; + _prog = d->prog; + break; + } + } + d++; + } + + return (_translate == NULL) ? EINA_FALSE : EINA_TRUE; +} + +int +main(int argc, char **argv) +{ + Eina_List *btl = NULL, *l; + char buf[4096]; + Bt *bt; + int cols[6] = { 0 }, len, i; + const char *func_color = ""; + const char *dir_color = ""; + const char *sep_color = ""; + const char *file_color = ""; + const char *line_color = ""; + const char *reset_color = ""; + const Translation_Desc desc[] = { +#ifdef ATOS_COMPATIBLE + { /* Mac OS X */ + .name = "atos", + .test = "atos --help &> /dev/null", + .func = _atos, + .prog = "atos" + }, + { /* Mac OS X */ + .name = "atos (old)", + .test = "xcrun atos --help &> /dev/null", + .func = _atos, + .prog = "xcrun atos" + }, +#endif + { /* GNU binutils */ + .name = "addr2line", + .test = "addr2line --help &> /dev/null", + .func = _addr2line, + .prog = "addr2line" + }, + { /* For imported GNU binutils */ + .name = "GNU addr2line", + .test = "gaddr2line --help &> /dev/null", + .func = _addr2line, + .prog = "addr2line" + }, + { NULL, NULL, NULL } /* Sentinel */ + }; + + eina_init(); + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-h")) + { + printf("Usage: eina_btlog [-n]\n" + " -n Do not use color escape codes\n" + " -C Do not show comments (non-bt fragments)\n" + " -c Show compact output format\n" + "\n" + "Provide addresses logged from EFL applications to stdin.\n" + "Example:\n\n" + "\tcat log.txt | eina_btlog\n" + "\n"); + eina_shutdown(); + return 0; + } + else if (!strcmp(argv[i], "-n")) color = EINA_FALSE; + else if (!strcmp(argv[i], "-C")) show_comments = EINA_FALSE; + else if (!strcmp(argv[i], "-c")) show_compact = EINA_TRUE; + } + + if (color) + { + func_color = EINA_COLOR_GREEN; + dir_color = EINA_COLOR_BLUE; + sep_color = EINA_COLOR_CYAN; + file_color = EINA_COLOR_WHITE; + line_color = EINA_COLOR_YELLOW; + reset_color = EINA_COLOR_RESET; + } + + if (!_translation_function_detect(desc)) + { + EINA_LOG_CRIT("Fail to determine a program to translate backtrace " + "into human-readable text"); + return 1; + } + + repeat: + while (fgets(buf, sizeof(buf) - 1, stdin)) + { + btl = bt_append(btl, buf); + if (show_compact) goto do_show; + bt = eina_list_last_data_get(btl); + if (bt && !bt->bin_dir) break; /* flush once first non-bt is found */ + } + + /* compute columns for expanded display */ + for (i = 0; i < 6; i++) cols[i] = 0; + EINA_LIST_FOREACH(btl, l, bt) + { + if (!bt->bin_dir) continue; + len = strlen(bt->bin_dir); + if (len > cols[0]) cols[0] = len; + len = strlen(bt->bin_name); + if (len > cols[1]) cols[1] = len; + + len = strlen(bt->file_dir); + if (len > cols[2]) cols[2] = len; + len = strlen(bt->file_name); + if (len > cols[3]) cols[3] = len; + + snprintf(buf, sizeof(buf), "%i", bt->line); + len = strlen(buf); + if (len > cols[4]) cols[4] = len; + + len = strlen(bt->func_name); + if (len > cols[5]) cols[5] = len; + } + + do_show: + EINA_LIST_FOREACH(btl, l, bt) + { + if (bt->comment && show_comments) + fputs(bt->comment, stdout); + if (!bt->bin_dir) continue; + + if (show_compact) + { + printf("%s%s%s (in %s%s%s:%s%d%s)\n", + func_color, bt->func_name, reset_color, + file_color, bt->file_name, reset_color, + line_color, bt->line, reset_color); + fflush(stdout); + continue; + } + + printf(" " + "%s%*s%s/%s%-*s%s" /* bin info */ + "| " + "%s%*s%s/%s%-*s%s" /* file info */ + ": " + "%s%*i%s" /* line info */ + " @ " + "%s%s%s()%s\n", /* func info */ + /* bin info */ + dir_color, cols[0], bt->bin_dir, sep_color, + file_color, cols[1], bt->bin_name, + reset_color, + /* file info */ + dir_color, cols[2], bt->file_dir, sep_color, + file_color, cols[3], bt->file_name, + reset_color, + /* line info */ + line_color, cols[4], bt->line, + reset_color, + /* func info */ + func_color, bt->func_name, + sep_color, + reset_color); + } + fflush(stdout); + EINA_LIST_FREE(btl, bt) + { + free(bt->bin_dir); + free(bt->bin_name); + free(bt->file_dir); + free(bt->file_name); + free(bt->func_name); + free(bt->comment); + free(bt); + } + /* if not EOF, then we just flushed due non-bt line, try again */ + if (!feof(stdin)) goto repeat; + + eina_shutdown(); + + return 0; +} diff --git a/src/bin/eina/eina_modinfo.c b/src/bin/eina/eina_modinfo.c deleted file mode 100644 index 943c92b3b7..0000000000 --- a/src/bin/eina/eina_modinfo.c +++ /dev/null @@ -1,57 +0,0 @@ -/* EINA - EFL data type library - * Copyright (C) 2016 Amitesh Singh - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; - * if not, see . - * - * --------------- usage --------------------- - * $ eina_modinfo - */ - -#include - -int main(int argc, char **argv) -{ - Eina_Module *em; - - eina_init(); - if (argc != 2) - { - fprintf(stderr, "Error: Missing module or filename\n"); - return 1; - } - - em = eina_module_new(argv[1]); - if (!em) - { - fprintf(stderr, "Error: Failed to open: %s\n", argv[1]); - return 2; - } - if (!eina_module_load(em)) - { - fprintf(stderr, "Error: Failed to load module\n"); - eina_module_free(em); - return 3; - } - - printf("version: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_ver")); - printf("description: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_desc")); - printf("license: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_license")); - printf("author: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_author")); - - eina_module_free(em); - eina_shutdown(); - - return 0; -} diff --git a/src/bin/eina/eina_modinfo/eina_modinfo.c b/src/bin/eina/eina_modinfo/eina_modinfo.c new file mode 100644 index 0000000000..943c92b3b7 --- /dev/null +++ b/src/bin/eina/eina_modinfo/eina_modinfo.c @@ -0,0 +1,57 @@ +/* EINA - EFL data type library + * Copyright (C) 2016 Amitesh Singh + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see . + * + * --------------- usage --------------------- + * $ eina_modinfo + */ + +#include + +int main(int argc, char **argv) +{ + Eina_Module *em; + + eina_init(); + if (argc != 2) + { + fprintf(stderr, "Error: Missing module or filename\n"); + return 1; + } + + em = eina_module_new(argv[1]); + if (!em) + { + fprintf(stderr, "Error: Failed to open: %s\n", argv[1]); + return 2; + } + if (!eina_module_load(em)) + { + fprintf(stderr, "Error: Failed to load module\n"); + eina_module_free(em); + return 3; + } + + printf("version: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_ver")); + printf("description: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_desc")); + printf("license: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_license")); + printf("author: %s\n", (char *)eina_module_symbol_get(em, "__EINA_MODULE_UNIQUE_ID_author")); + + eina_module_free(em); + eina_shutdown(); + + return 0; +} diff --git a/src/lib/eina/CMakeLists.txt b/src/lib/eina/CMakeLists.txt index 1a57243d33..b1981c801b 100644 --- a/src/lib/eina/CMakeLists.txt +++ b/src/lib/eina/CMakeLists.txt @@ -3,7 +3,11 @@ set(INCLUDE_DIRECTORIES ${VG_INCLUDE_DIRS}) set(LIBRARIES - ${VG_LIBRARIES} + ${VG_LIBRARIES}) + +set(PUBLIC_LIBRARIES + m + dl pthread) set(PUBLIC_HEADERS -- cgit v1.2.1