aboutsummaryrefslogblamecommitdiffstatshomepage
path: root/%HOME%/.bash_utils/cxx.sh
blob: 3aaa9180aa8b52b92846f6f4198f5e81ceefa2d3 (plain) (tree)
1
2
3
4
5
6
7
8

                   
                                                        
                                                
                                                             

                                    
                      





                                         
                           


                        












                                                             
 
            
 
                           


                                              


                                         


                                                          

               
                            

        
                                                                                                                           

 
        
                                         
 
                                                          
                         
                            
                        
                    
                      

                            







                           
                                   

                                                                          

                            

                          


                               
               


                                    



                                



                            
               

                     
              
                                   



                  
                    
 
                                         
                                                              








                                                           
                                                                           




                                                
                                                                                   
      
 



                                            







                                                                           

      


                                       



                                                                                 


                                  
                                                                                
 
                                               

                                           
 
                                                    

 
          
                                         



                                                                 
 
 




























                                                         
























                                                                              


                                            







                                                                                  

 





                                             
 
#!/usr/bin/env bash

# Copyright (c) 2016 Egor Tensin <Egor.Tensin@gmail.com>
# This file is part of the "linux-home" project.
# For details, see https://github.com/egor-tensin/linux-home.
# Distributed under the MIT License.

_runc_os_is_cygwin() (
    set -o errexit -o nounset -o pipefail
    local os
    os="$( uname -o )"
    test 'Cygwin' = "$os"
)

if _runc_os_is_cygwin; then
    _runc_exe_ext='.exe'
fi

runc_use_gcc() {
    runc_compiler=gcc
    runcxx_compiler=g++
    declare -ag runc_flags=('-Wall' '-Wextra')
    declare -ag runcxx_flags=('-Wall' '-Wextra' '-std=c++14')
}

runc_use_clang() {
    runc_compiler=clang
    runcxx_compiler=clang++
    declare -ag runc_flags=('-Wall' '-Wextra')
    declare -ag runcxx_flags=('-Wall' '-Wextra')
}

runc_use_gcc

_runc_get_absolute_path() {
    readlink -z --canonicalize-missing -- "$@"
}

_runc_usage() (
    set -o errexit -o nounset -o pipefail

    local prefix="${FUNCNAME[0]}"
    [ "${#FUNCNAME[@]}" -gt 1 ] && prefix="${FUNCNAME[1]}"

    local msg
    for msg; do
        echo "$prefix: $msg"
    done

    echo "usage: $prefix [-h|--help] [-c|--comp-arg ARG]... [-I DIR]... [-L DIR]... [-l LIB]... PATH... [-- [PROG_ARG]...]"
)

runc() (
    set -o errexit -o nounset -o pipefail

    local -a c_flags=(${runc_flags[@]+"${runc_flags[@]}"})
    local -a src_files=()
    local -a include_dirs=()
    local -a lib_dirs=()
    local -a libs=()
    local -a prog_args

    while [ "$#" -gt 0 ]; do
        local key="$1"
        shift

        case "$key" in
            -h|--help)
                _runc_usage
                return 0
                ;;
            -c|--comp-arg|-I|-L|-l)
                if [ "$#" -eq 0 ]; then
                    _runc_usage "missing argument for parameter: $key" >&2
                    return 1
                fi
                ;;&
            -c|--comp-arg)
                c_flags+=("$1")
                shift
                ;;
            -I)
                include_dirs+=("$1")
                shift
                ;;
            -L)
                lib_dirs+=("$1")
                shift
                ;;
            -l)
                libs+=("$1")
                shift
                ;;
            --)
                break
                ;;
            *)
                src_files+=("$key")
                ;;
        esac
    done

    prog_args=("$@")

    if [ "${#src_files[@]}" -eq 0 ]; then
        _runc_usage 'at least one source file is required' >&2
        return 1
    fi

    local -a _src_files=(${src_files[@]+"${src_files[@]}"})
    src_files=()

    local src_file
    while IFS= read -d '' -r src_file; do
        src_files+=("$src_file")
    done < <( _runc_get_absolute_path ${_src_files[@]+"${_src_files[@]}"} )

    if [ "${#include_dirs[@]}" -gt 0 ]; then
        local include_dir
        while IFS= read -d '' -r include_dir; do
            c_flags+=("-I$include_dir")
        done < <( _runc_get_absolute_path ${include_dirs[@]+"${include_dirs[@]}"} )
    fi

    if [ "${#lib_dirs[@]}" -gt 0 ]; then
        local lib_dir
        while IFS= read -d '' -r lib_dir; do
            c_flags+=("-L$lib_dir")
        done < <( _runc_get_absolute_path ${lib_dirs[@]+"${lib_dirs[@]}"} )
    fi

    if [ "${#libs[@]}" -gt 0 ]; then
        local lib
        for lib in ${libs[@]+"${libs[@]}"}; do
            c_flags+=("-l$lib")
        done
    fi

    local build_dir
    build_dir="$( mktemp --directory )"

    local rm_build_dir
    rm_build_dir="$( printf -- 'popd > /dev/null && rm -rf -- %q' "$build_dir" )"

    trap "$rm_build_dir" EXIT
    pushd "$build_dir" > /dev/null

    local output_name
    output_name="$( mktemp --tmpdir=. -- "${FUNCNAME[0]}XXX${_runc_exe_ext-}" )"

    "${runc_compiler:-gcc}" -o "$output_name" \
        ${src_files[@]+"${src_files[@]}"} \
        ${c_flags[@]+"${c_flags[@]}"}

    "$output_name" ${prog_args[@]+"${prog_args[@]}"}
)

runcxx() (
    set -o errexit -o nounset -o pipefail
    local -a runc_flags=(${runcxx_flags[@]+"${runcxx_flags[@]}"})
    BASH_ENV=<( declare -p runc_flags ) \
        runc_compiler="${runcxx_compiler:-g++}" \
        runc "$@"
)

_runc_gdb() (
    set -o errexit -o nounset -o pipefail

    if [ "$#" -ne 2 ]; then
        echo "usage: ${FUNCNAME[0]} BINARY CORE_DUMP" >&2
        return 1
    fi

    local binary_path="$1"
    local core_dump_path="$2"

    gdb "$binary_path" "$core_dump_path"
)

_runc_lldb() (
    set -o errexit -o nounset -o pipefail

    if [ "$#" -ne 2 ]; then
        echo "usage: ${FUNCNAME[0]} BINARY CORE_DUMP" >&2
        return 1
    fi

    local binary_path="$1"
    local core_dump_path="$2"

    lldb -f "$binary_path" -c "$core_dump_path"
)

runc_debug() (
    set -o errexit -o nounset -o pipefail

    if [ "$#" -ne 1 ]; then
        echo "usage: ${FUNCNAME[0]} BINARY" >&2
        return 1
    fi

    local binary_path="$1"
    binary_path="$( readlink --canonicalize-missing -- "$binary_path" )"

    local crash_path
    crash_path="$( str_replace "$binary_path" '/' '_' )"
    crash_path="$crash_path.$UID.crash"
    crash_path="/var/crash/$crash_path"

    if [ ! -r "$crash_path" ]; then
        echo "${FUNCNAME[0]}: $crash_path doesn't exist or isn't readable" >&2
        return 1
    fi

    local crash_dir
    crash_dir="$( mktemp --directory )"

    local rm_crash_dir
    rm_crash_dir="$( printf -- 'rm -rf -- %q' "$crash_dir" )"
    trap "$rm_crash_dir" EXIT

    apport-unpack "$crash_path" "$crash_dir"
    local core_dump_path="$crash_dir/CoreDump"

    if [ ! -r "$core_dump_path" ]; then
        echo "${FUNCNAME[0]}: $core_dump_path doesn't exist or isn't readable" >&2
        return 1
    fi

    "${DEBUG_FUNCTION:-_runc_gdb}" "$binary_path" "$core_dump_path"
)

runc_gdb() {
    DEBUG_FUNCTION=_runc_gdb runc_debug "$@"
}

runc_lldb() {
    DEBUG_FUNCTION=_runc_lldb runc_debug "$@"
}