Skip to content

Commit

Permalink
run clang-tidy on travis
Browse files Browse the repository at this point in the history
  • Loading branch information
Dane Springmeyer committed Aug 18, 2017
1 parent 5baa948 commit bdd45a6
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .clang-tidy
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
Checks: '*'
WarningsAsErrors: '*'
HeaderFilterRegex: '\/src\/'
AnalyzeTemporaryDtors: false
CheckOptions:
- key: google-readability-braces-around-statements.ShortStatementLines
value: '1'
- key: google-readability-function-size.StatementThreshold
value: '800'
- key: google-readability-namespace-comments.ShortNamespaceLines
value: '10'
- key: google-readability-namespace-comments.SpacesBeforeComments
value: '2'
- key: modernize-loop-convert.MaxCopySize
value: '16'
- key: modernize-loop-convert.MinConfidence
value: reasonable
- key: modernize-loop-convert.NamingStyle
value: CamelCase
- key: modernize-pass-by-value.IncludeStyle
value: llvm
- key: modernize-replace-auto-ptr.IncludeStyle
value: llvm
- key: modernize-use-nullptr.NullMacros
value: 'NULL'
...

1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ script:
make clean;
make gyp;
fi
- ./scripts/clang-tidy.sh

after_script:
- if [[ ${COVERAGE:-0} == 'True' ]]; then
Expand Down
45 changes: 45 additions & 0 deletions scripts/clang-tidy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash

set -eu
set -o pipefail

# https://clang.llvm.org/extra/clang-tidy/

# to speed up re-runs, only re-create environment if needed
if [[ ! -f local.env ]]; then
# automatically setup environment
./scripts/setup.sh --config local.env
fi

# source the environment
source local.env

PATH_TO_CLANG_TIDY_SCRIPT="$(pwd)/mason_packages/.link/share/run-clang-tidy.py"

# to speed up re-runs, only install clang-tidy if needed
if [[ ! -f PATH_TO_CLANG_TIDY_SCRIPT ]]; then
# The MASON_LLVM_RELEASE variable comes from `local.env`
mason install clang-tidy ${MASON_LLVM_RELEASE}
# We link the tools to make it easy to know ${PATH_TO_CLANG_TIDY_SCRIPT}
mason link clang-tidy ${MASON_LLVM_RELEASE}
fi

# build the compile_commands.json file if it does not exist
if [[ ! -f build/compile_commands.json ]]; then
# We need to clean otherwise when we make the project
# will will not see all the compile commands
make clean
# Create the build directory to put the compile_commands in
# We do this first to ensure it is there to start writing to
# immediately (make make not create it right away)
mkdir -p build
# Run make, pipe the output to the generate_compile_commands.py
# and drop them in a place that clang-tidy will automatically find them
make | scripts/generate_compile_commands.py > build/compile_commands.json
fi

# change into the build directory so that clang-tidy can find the files
# at the right paths (since this is where the actual build happens)
cd build
${PATH_TO_CLANG_TIDY_SCRIPT} -fix

39 changes: 39 additions & 0 deletions scripts/generate_compile_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#!/usr/bin/env python

import sys
import json
import os
import re

# Script to generate compile_commands.json based on Makefile output
# Works by accepting Makefile output from stdin, parsing it, and
# turning into json records. These are then printed to stdout.
# More details on the compile_commands format at:
# https://clang.llvm.org/docs/JSONCompilationDatabase.html
#
# Note: make must be run in verbose mode, e.g. V=1 make or VERBOSE=1 make
#
# Usage with node-cpp-skel:
#
# make | ./scripts/generate_compile_commands.py > build/compile_commands.json

# These work for node-cpp-skel to detect the files being compiled
# They may need to be modified if you adapt this to another tool
matcher = re.compile('^(.*) (.+cpp)')
build_dir = os.path.join(os.getcwd())
TOKEN_DENOTING_COMPILED_FILE='c++'

def generate():
compile_commands = []
for line in sys.stdin.readlines():
if TOKEN_DENOTING_COMPILED_FILE in line:
match = matcher.match(line)
compile_commands.append({
"directory": build_dir,
"command": line.strip(),
"file": os.path.normpath(os.path.join(build_dir,match.group(2)))
})
print json.dumps(compile_commands,indent=4)

if __name__ == '__main__':
generate()
132 changes: 132 additions & 0 deletions scripts/setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env bash

set -eu
set -o pipefail

export MASON_RELEASE="${MASON_RELEASE:-v0.14.1}"
export MASON_LLVM_RELEASE="${MASON_LLVM_RELEASE:-4.0.1}"

PLATFORM=$(uname | tr A-Z a-z)
if [[ ${PLATFORM} == 'darwin' ]]; then
PLATFORM="osx"
fi

MASON_URL="https://s3.amazonaws.com/mason-binaries/${PLATFORM}-$(uname -m)"

llvm_toolchain_dir="$(pwd)/.toolchain"

function run() {
local config=${1}
# unbreak bash shell due to rvm bug on osx: https://github.com/direnv/direnv/issues/210#issuecomment-203383459
# this impacts any usage of scripts that are source'd (like this one)
if [[ "${TRAVIS_OS_NAME:-}" == "osx" ]]; then
echo 'shell_session_update() { :; }' > ~/.direnvrc
fi

#
# COMPILER TOOLCHAIN
#

# We install clang++ without the mason client for a couple reasons:
# 1) decoupling makes it viable to use a custom branch of mason that might
# modify the upstream s3 bucket in a such a way that does not give
# it access to build tools like clang++
# 2) Allows us to short-circuit and use a global clang++ install if it
# is available to save space for local builds.
GLOBAL_CLANG="${HOME}/.mason/mason_packages/${PLATFORM}-$(uname -m)/clang++/${MASON_LLVM_RELEASE}"
GLOBAL_LLVM="${HOME}/.mason/mason_packages/${PLATFORM}-$(uname -m)/llvm/${MASON_LLVM_RELEASE}"
if [[ -d ${GLOBAL_LLVM} ]]; then
echo "Detected '${GLOBAL_LLVM}/bin/clang++', using it"
local llvm_toolchain_dir=${GLOBAL_LLVM}
elif [[ -d ${GLOBAL_CLANG} ]]; then
echo "Detected '${GLOBAL_CLANG}/bin/clang++', using it"
local llvm_toolchain_dir=${GLOBAL_CLANG}
elif [[ -d ${GLOBAL_CLANG} ]]; then
echo "Detected '${GLOBAL_CLANG}/bin/clang++', using it"
local llvm_toolchain_dir=${GLOBAL_CLANG}
elif [[ ! -d ${llvm_toolchain_dir} ]]; then
BINARY="${MASON_URL}/clang++/${MASON_LLVM_RELEASE}.tar.gz"
echo "Downloading ${BINARY}"
mkdir -p ${llvm_toolchain_dir}
curl -sSfL ${BINARY} | tar --gunzip --extract --strip-components=1 --directory=${llvm_toolchain_dir}
fi

#
# MASON
#

function setup_mason() {
local install_dir=${1}
local mason_release=${2}
mkdir -p ${install_dir}
curl -sSfL https://github.com/mapbox/mason/archive/${mason_release}.tar.gz | tar --gunzip --extract --strip-components=1 --directory=${install_dir}
}

setup_mason $(pwd)/.mason ${MASON_RELEASE}

#
# ENV SETTINGS
#

echo "export PATH=${llvm_toolchain_dir}/bin:$(pwd)/.mason:$(pwd)/mason_packages/.link/bin:"'${PATH}' > ${config}
echo "export CXX=${llvm_toolchain_dir}/bin/clang++" >> ${config}
echo "export MASON_RELEASE=${MASON_RELEASE}" >> ${config}
echo "export MASON_LLVM_RELEASE=${MASON_LLVM_RELEASE}" >> ${config}
# https://github.com/google/sanitizers/wiki/AddressSanitizerAsDso
RT_BASE=${llvm_toolchain_dir}/lib/clang/${MASON_LLVM_RELEASE}/lib/$(uname | tr A-Z a-z)/libclang_rt
if [[ $(uname -s) == 'Darwin' ]]; then
RT_PRELOAD=${RT_BASE}.asan_osx_dynamic.dylib
else
RT_PRELOAD=${RT_BASE}.asan-x86_64.so
fi
echo "export MASON_LLVM_RT_PRELOAD=${RT_PRELOAD}" >> ${config}
SUPPRESSION_FILE="/tmp/leak_suppressions.txt"
echo "leak:__strdup" > ${SUPPRESSION_FILE}
echo "leak:v8::internal" >> ${SUPPRESSION_FILE}
echo "leak:node::CreateEnvironment" >> ${SUPPRESSION_FILE}
echo "leak:node::Init" >> ${SUPPRESSION_FILE}
echo "export ASAN_SYMBOLIZER_PATH=${llvm_toolchain_dir}/bin/llvm-symbolizer" >> ${config}
echo "export MSAN_SYMBOLIZER_PATH=${llvm_toolchain_dir}/bin/llvm-symbolizer" >> ${config}
echo "export UBSAN_OPTIONS=print_stacktrace=1" >> ${config}
echo "export LSAN_OPTIONS=suppressions=${SUPPRESSION_FILE}" >> ${config}
echo "export ASAN_OPTIONS=symbolize=1:abort_on_error=1:detect_container_overflow=1:check_initialization_order=1:detect_stack_use_after_return=1" >> ${config}
echo 'export MASON_SANITIZE="-fsanitize=address,undefined -fno-sanitize=vptr,function"' >> ${config}
echo 'export MASON_SANITIZE_CXXFLAGS="${MASON_SANITIZE} -fno-sanitize=vptr,function -fsanitize-address-use-after-scope -fno-omit-frame-pointer -fno-common"' >> ${config}
echo 'export MASON_SANITIZE_LDFLAGS="${MASON_SANITIZE}"' >> ${config}

exit 0
}

function usage() {
>&2 echo "Usage"
>&2 echo ""
>&2 echo "$ ./scripts/setup.sh --config local.env"
>&2 echo "$ source local.env"
>&2 echo ""
exit 1
}

if [[ ! ${1:-} ]]; then
usage
fi

# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash
for i in "$@"
do
case $i in
--config)
if [[ ! ${2:-} ]]; then
usage
fi
shift
run $@
;;
-h | --help)
usage
shift
;;
*)
usage
;;
esac
done

0 comments on commit bdd45a6

Please sign in to comment.