10528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#!/bin/sh
20528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
30528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Copyright (C) 2011 The Android Open Source Project
40528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
50528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Licensed under the Apache License, Version 2.0 (the "License");
60528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# you may not use this file except in compliance with the License.
70528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# You may obtain a copy of the License at
80528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
90528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#      http://www.apache.org/licenses/LICENSE-2.0
100528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
110528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Unless required by applicable law or agreed to in writing, software
120528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# distributed under the License is distributed on an "AS IS" BASIS,
130528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# See the License for the specific language governing permissions and
150528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# limitations under the License.
160528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
170528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# gen-system-symbols.sh
180528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
190528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# This tool is used to read the shared library from a source directory
200528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# (SRC) and extract the list of functions and variables.
210528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
220528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Then, for each library, it will generate in (DST) two text files
230528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# named <library>.functions.txt and <library>.variables.txt
240528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
250528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
260528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Only runs on Linux because it requires the "readelf" utility
270528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner#
280528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
290528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner. `dirname $0`/prebuilt-common.sh
300528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
310528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerVERBOSE=no
320528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerVERBOSE2=no
330528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
340528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerPROGRAM_PARAMETERS="<src-dir> <dst-dir>"
350528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerPROGRAM_DESCRIPTION=\
360528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner"This program is used to parse all shared libraries in <src-dir>
370528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerand extract, for each one of them, the list of functions and variables
380528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerthat it exports.
390528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
400528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerFor some of these libraries, it will remove symbols that are not meant
410528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerto be imported (unless you use --no-symbol-filtering)
420528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
430528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerThese lists will then be saved into two files:
440528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
450528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner  <dst-dir>/<libname>.functions.txt
460528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner  <dst-dir>/<libname>.variables.txt
470528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner"
480528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
490528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerNO_FILTERING=
500528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerregister_var_option "--no-symbol-filtering" NO_FILTERING "Disable symbol filtering"
510528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
520528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerextract_parameters "$@"
530528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
540528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerparse_params ()
550528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
560528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    SRCDIR=$1
570528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    DSTDIR=$2
580528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
590528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    if [ -z "$SRCDIR" ]; then
600528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        dump "ERROR: Missing first parameter (source directory path), see --help"
610528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        exit 1
620528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    fi
630528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
640528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    if [ -z "$DSTDIR" ]; then
650528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        dump "ERROR: Missing second parameter (destination directory path), see --help"
660528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        exit 1
670528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    fi
680528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
690528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    if [ ! -d "$SRCDIR" ]; then
700528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        dump "ERROR: Not a source directory: $SRCDIR"
710528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        exit 1
720528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    fi
730528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
740528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    mkdir -p $DSTDIR
750528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    fail_panic "Could not create destination directory: $DSTDIR"
760528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
770528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
780528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerparse_params $PARAMETERS
790528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
800528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerREADELF=readelf
810528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
820528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# $1: shared library path
830528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerget_library_functions ()
840528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
85e9f5fc93f45682793836b68b277b0c451b92f885David 'Digit' Turner    $READELF -s -D -W $1 | awk '$5 ~ /FUNC/ && $6 ~ /GLOBAL|WEAK/ && $8 !~ /UND/ { print $9; }' | sort -u
860528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
870528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
880528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# $1: shared library path
890528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerget_library_variables ()
900528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
91e9f5fc93f45682793836b68b277b0c451b92f885David 'Digit' Turner    $READELF -s -D -W $1 | awk '$5 ~ /OBJECT/ && $6 ~ /GLOBAL|WEAK/ && $8 !~ /UND/ { print $9; }' | sort -u
920528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
930528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
940528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Temp file used to list shared library symbol exclusions
950528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# See set_symbol_excludes and extract_shared_library_xxxx functions below
960528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerSYMBOL_EXCLUDES=/tmp/ndk-$USER/ndk-symbol-excludes.txt
970528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
980528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Temp file used to list shared library symbol inclusions, these
990528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# are essentially overrides to the content of SYMBOL_EXCLUDES
1000528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerSYMBOL_INCLUDES=/tmp/ndk-$USER/ndk-symbol-includes.txt
1010528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1020528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Temp file used to filter symbols
1030528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' TurnerSYMBOL_TMPFILE=/tmp/ndk-$USER/ndk-symbols-list.txt
1040528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1050528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Reset the symbol exclusion list to its default
1060528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerreset_symbol_excludes ()
1070528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1080528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    # By default, do not export C++ mangled symbol, which all start with _Z
1090528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    echo '^_Z' > $SYMBOL_EXCLUDES
1100528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1110528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    # __INIT_ARRAY__ and __FINI_ARRAY__ are special symbols that should
1120528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    # normally be hidden.
1130528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    echo "^__INIT_ARRAY__" >> $SYMBOL_EXCLUDES
1140528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    echo "^__FINI_ARRAY__" >> $SYMBOL_EXCLUDES
1150528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    > $SYMBOL_INCLUDES
1160528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1170528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1180528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Add new exclusion patterns to SYMBOL_EXCLUDES
1190528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerset_symbol_excludes ()
1200528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1210528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (echo "$@" | tr ' ' '\n') >> $SYMBOL_EXCLUDES
1220528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1230528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1240528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Add new inclusion patterns to SYMBOL_INCLUDES
1250528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerset_symbol_includes ()
1260528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1270528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (echo "$@" | tr ' ' '\n') >> $SYMBOL_INCLUDES
1280528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1290528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1300528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Clear symbol exclusion/inclusion files
1310528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerclear_symbol_excludes ()
1320528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1330528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    rm -f $SYMBOL_EXCLUDES $SYMBOL_INCLUDES
1340528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1350528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1360528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Filter the list of symbols from a file
1370528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# $1: path to symbol list file
1380528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerfilter_symbols ()
1390528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1400528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (grep -v -f $SYMBOL_EXCLUDES $1 ; grep -f $SYMBOL_INCLUDES $1) | sort -u
1410528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1420528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1430528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# $1: Library name
1440528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# $2+: List of symbols (functions or variables)
1450528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner# Out: sorted list of filtered symbols, based on library name
1460528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerfilter_library_symbols ()
1470528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner{
1480528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    local LIB=$1
1490528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    shift
1500528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    local SYMBOLS="$@"
1510528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (echo "$SYMBOLS" | tr ' ' '\n' | sort -u) > $SYMBOL_TMPFILE
1520528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1530528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    reset_symbol_excludes
1540528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1550528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    case $LIB in
1560528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        libc.so)
1570528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            # Remove a few internal symbols that should not be exposed
1580528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            # from the C library (we plan to clean that up soon by using the
1590528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            # "hidden" visibility attribute in the near future).
1600528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            #
1610528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            set_symbol_excludes \
1620528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner                '^the_' '^dns_' 'load_domain_search_list' 'res_get_dns_changed' \
1630528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner                '^_resolv_cache' '^_dns_getht' '^_thread_atexit' \
1640528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner                '^free_malloc_leak_info' 'fake_gmtime_r' 'fake_localtime_r' \
1650528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner                '^gAllocationsMutex' '^gHashTable' '^gMallocLeakZygoteChild'
1660528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            ;;
1670528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        libstdc++.so)
1680528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            # This is the only library that is allowed to export C++ symbols for now.
1690528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            set_symbol_includes '^_Z.*'
1700528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            ;;
1710528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        liblog.so)
1720528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            set_symbol_excludes '^.*'         # exclude everything
1730528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            set_symbol_includes '^__android_' # except __android_xxxx functions
1740528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            ;;
1750528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        libOpenSLES.so)
1760528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            set_symbol_excludes '^_' '^MPH_' # remove MPH_to_xxx definitions
1770528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner            ;;
1780528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    esac
1790528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    filter_symbols "$SYMBOL_TMPFILE"
1800528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner}
1810528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner
1820528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerfor LIB in $(cd $SRCDIR && ls lib*.so); do
1830528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    SRCLIB=$SRCDIR/$LIB
1840528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    log "Extracting symbols from $LIB"
1850528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    FUNCS=$(get_library_functions $SRCLIB)
1860528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    VARS=$(get_library_variables $SRCLIB)
1870528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    if [ -z "$NO_FILTERING" ]; then
1880528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        FUNCS=$(filter_library_symbols $LIB $FUNCS)
1890528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner        VARS=$(filter_library_symbols $LIB $VARS)
1900528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    fi
1910528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    NUMFUNCS=$(echo $FUNCS | wc -w)
1920528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    NUMVARS=$(echo $VARS | wc -w)
1930528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    log "    Found $NUMFUNCS functions and $NUMVARS variables"
1940528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (echo "$FUNCS" | tr ' ' '\n') > $DSTDIR/$LIB.functions.txt
1950528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turner    (echo "$VARS" | tr ' ' '\n') > $DSTDIR/$LIB.variables.txt
1960528f4d870022e4c3ee4e32714a7ef88908e310fDavid 'Digit' Turnerdone
197