You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@kudu.apache.org by ad...@apache.org on 2016/01/21 04:04:10 UTC

[2/3] incubator-kudu git commit: cmake: add support for out-of-tree builds

cmake: add support for out-of-tree builds

One of cmake's selling points is its ease of isolating source trees from
build directories so that one tree can be used for multiple builds, each
configured differently. With judicious git use, each build can even be
based on different git hashes. Many cmake-based projects take care to
preserve this isolation, some even go as far as prohibiting in-tree builds
so that developers are really forced to isolate build files from source
files. Today's Kudu does not build out-of-tree; this patch fixes that, and
then some.

For isolation to work we must respect the difference between
CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR. For in-tree builds they are
identical, and perhaps that's why, over time, we've chosen the former when
we should have chosen the latter. The bulk of the patch deals with this, and
with the resulting fallout (e.g. with generated .pb.h files now in the build
directory, it needs to be added to include_directories()).

The other major (and disruptive) part of the patch is this: like some
cmake-based projects, we will soon prohibit the use of the source tree as a
build directory. This ensures that all build output is well isolated from
source code. It also helps deal with an annoying cmake quirk: if the source
tree is used as a build directory and thus winds up containing a
CMakeCache.txt file, future out-of-tree builds will fail. In preparation for
this change, I've updated various "end to end" build scripts. The most
annoying was make_site.sh, which I'm still not sure if I got right.

Finally, some additional notes:
- Build output is no longer in .gitignore, so that we'll notice if it leaks
  into the source tree.
- With support for multiple build directories now baked-in, I've removed the
  build/<build_type> approximation we used to do. Build output continues to
  go into a 'latest' subdirectory for compatibility with existing scripts.
- Due to the loss of the direct link between the build directory and source
  tree, unit tests (and their resources) must now exist in the build
  directory. This was already the case for executables, but not for scripts,
  which were executed from the source tree. Sadly, add_test() doesn't create
  a cmake target, so I was forced to symlink during cmake rather than make.

Change-Id: I76e17a1102b79ac0e25a505b54347db3bb436ede
Reviewed-on: http://gerrit.cloudera.org:8080/1755
Tested-by: Internal Jenkins
Reviewed-by: Todd Lipcon <to...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/incubator-kudu/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-kudu/commit/3e8d29f4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-kudu/tree/3e8d29f4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-kudu/diff/3e8d29f4

Branch: refs/heads/master
Commit: 3e8d29f4dd6d56da7be440730f6015b932e54b4b
Parents: 52c0f28
Author: Adar Dembo <ad...@cloudera.com>
Authored: Thu Jan 7 17:46:45 2016 -0800
Committer: Adar Dembo <ad...@cloudera.com>
Committed: Wed Jan 20 23:47:49 2016 +0000

----------------------------------------------------------------------
 .gitignore                              |  44 ++--------
 CMakeLists.txt                          |  67 ++++++++--------
 README.adoc                             |  84 +++++++++++--------
 build-support/jenkins/build-and-test.sh |  73 +++++++++--------
 build-support/run-test.sh               |  36 +++++----
 cmake_modules/FindKRPC.cmake            |   4 -
 cmake_modules/FindProtobuf.cmake        |   4 -
 docs/installation.adoc                  |  59 +++++++++++---
 docs/support/scripts/make_docs.sh       | 115 +++++++++++++++------------
 docs/support/scripts/make_site.sh       |  43 ++++------
 python/kudu/tests/common.py             |   2 +-
 python/setup.py                         |  14 ++--
 src/kudu/client/CMakeLists.txt          |   4 +-
 src/kudu/client/client_samples-test.sh  |   8 +-
 src/kudu/client/client_symbol-test.sh   |   3 +-
 src/kudu/codegen/CMakeLists.txt         |  19 +++--
 src/kudu/scripts/benchmarks.sh          |  24 +++---
 src/kudu/scripts/tpch.sh                |  18 +++--
 src/kudu/twitter-demo/CMakeLists.txt    |   4 +
 src/kudu/twitter-demo/parser-test.cc    |   4 +-
 src/kudu/util/CMakeLists.txt            |   2 +-
 21 files changed, 332 insertions(+), 299 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/.gitignore
----------------------------------------------------------------------
diff --git a/.gitignore b/.gitignore
index 7b7c2aa..a55a351 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,47 +1,19 @@
-*.pb.cc
-*.pb.h
+# Most common in-tree build directory.
+#
+# Note: build output files are not explicitly listed here because they are
+# expected to fall within in the build directory (and indeed, if they're
+# outside for some reason, we want to know as it's likely an error).
+build/
 
-Makefile
-CMakeFiles
-CMakeCache.txt
-cmake_install.cmake
-CTestTestfile.cmake
-TAGS
-tags
-cscope.*
-Testing
 perf.data
 perf.data.old
 oprofile_data
-*.service.cc
-*.service.h
-*.proxy.cc
-*.proxy.h
-build/
 .ycm_extra_conf.pyc
 *.kdev4
 .kdev4/
 .metadata/
 *.iml
 
-# CMake-generated Clang compilation database file
-compile_commands.json
-
-# CMake-generated library export headers
-*_export.h
-
-# CMake-generated "make install" file
-install_manifest.txt
-
-# CMake-generated library export make file
-clientConfig.cmake
-
-# CMake-generated ninja build stuff
-.ninja_deps
-.ninja_log
-build.ninja
-rules.ninja
-
 # VIM/emacs stuff
 *.swp
 *~
@@ -61,7 +33,3 @@ www/tracing.*
 python/kudu/*.so
 python/kudu/*.cpp
 *.py[ocd]
-
-# Docs-generation bundler metadata
-docs/support/scripts/.bundle/
-docs/support/scripts/.gem/

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f803da7..aec6079 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -368,18 +368,8 @@ if ("${KUDU_LINK}" STREQUAL "d")
 endif()
 
 # set compile output directory
-string (TOLOWER ${CMAKE_BUILD_TYPE} BUILD_SUBDIR_NAME)
-set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/build/${BUILD_SUBDIR_NAME}/")
-
-# Link build/latest to the current build directory, to avoid developers
-# accidentally running the latest debug build when in fact they're building
-# release builds.
-FILE(MAKE_DIRECTORY ${BUILD_OUTPUT_ROOT_DIRECTORY})
-if (NOT APPLE)
-  set(MORE_ARGS "-T")
-endif()
-EXECUTE_PROCESS(COMMAND ln ${MORE_ARGS} -sf ${BUILD_OUTPUT_ROOT_DIRECTORY}
-  ${CMAKE_CURRENT_SOURCE_DIR}/build/latest)
+set(BUILD_OUTPUT_ROOT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/latest")
+file(MAKE_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
 
 # where to put generated archives (.a files)
 set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
@@ -391,6 +381,8 @@ set(LIBRARY_OUTPUT_DIRECTORY "${BUILD_OUTPUT_ROOT_DIRECTORY}")
 
 # where to put generated binaries
 set(EXECUTABLE_OUTPUT_PATH "${BUILD_OUTPUT_ROOT_DIRECTORY}")
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/src)
 include_directories(src)
 
 ############################################################
@@ -553,7 +545,14 @@ function(ADD_KUDU_TEST REL_TEST_NAME)
     target_link_libraries(${TEST_NAME} ${KUDU_TEST_LINK_LIBS})
   else()
     # No executable, just invoke the test (probably a script) directly.
-    set(TEST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME})
+    get_filename_component(TEST_NAME_WITH_EXT ${REL_TEST_NAME} NAME)
+    set(TEST_PATH "${EXECUTABLE_OUTPUT_PATH}/${TEST_NAME_WITH_EXT}")
+
+    # Ideally this would run only when the test is built, not when cmake runs,
+    # but add_test() doesn't yield a target (if it did, that target could depend
+    # on an add_custom_command() that copies the test file into place).
+    execute_process(COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/${REL_TEST_NAME}
+      ${EXECUTABLE_OUTPUT_PATH})
   endif()
 
   add_test(${TEST_NAME}
@@ -632,12 +631,14 @@ function(ADD_THIRDPARTY_LIB LIB_NAME)
 endfunction()
 
 # Look in thirdparty prefix paths before anywhere else for system dependencies.
-set(THIRDPARTY_PREFIX ${CMAKE_SOURCE_DIR}/thirdparty/installed)
+set(THIRDPARTY_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/installed)
 set(CMAKE_PREFIX_PATH ${THIRDPARTY_PREFIX} ${CMAKE_PREFIX_PATH})
 if (${KUDU_USE_TSAN})
-  set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/thirdparty/installed-deps-tsan ${CMAKE_PREFIX_PATH})
+  set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/installed-deps-tsan
+      ${CMAKE_PREFIX_PATH})
 else()
-  set(CMAKE_PREFIX_PATH ${CMAKE_SOURCE_DIR}/thirdparty/installed-deps ${CMAKE_PREFIX_PATH})
+  set(CMAKE_PREFIX_PATH ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/installed-deps
+      ${CMAKE_PREFIX_PATH})
 endif()
 
 ## Cyrus SASL
@@ -682,8 +683,6 @@ ADD_THIRDPARTY_LIB(gmock
   SHARED_LIB ${GMOCK_SHARED_LIBRARY})
 
 ## Protobuf
-set(PROTO_SRC_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/src)
-set(PROTO_DST_ROOT ${CMAKE_CURRENT_BINARY_DIR}/src)
 find_package(Protobuf REQUIRED)
 include_directories(SYSTEM ${PROTOBUF_INCLUDE_DIR})
 ADD_THIRDPARTY_LIB(protobuf
@@ -693,7 +692,6 @@ ADD_THIRDPARTY_LIB(protoc
   STATIC_LIB "${PROTOBUF_PROTOC_STATIC_LIBRARY}"
   SHARED_LIB "${PROTOBUF_PROTOC_LIBRARY}"
   DEPS protobuf)
-
 find_package(KRPC REQUIRED)
 
 ## Snappy
@@ -859,28 +857,34 @@ set(KUDU_TEST_LINK_LIBS ${KUDU_MIN_TEST_LIBS})
 # "make ctags" target
 ############################################################
 if (UNIX)
-  add_custom_target(ctags ctags -R --languages=c++,c --exclude=thirdparty/installed)
+  add_custom_target(ctags ctags --languages=c++,c -L
+    `find ${CMAKE_CURRENT_SOURCE_DIR}/src
+          ${CMAKE_CURRENT_BINARY_DIR}/src`)
 endif (UNIX)
 
 ############################################################
 # "make etags" target
+#
+# Requires the exuberant-ctags system package.
 ############################################################
 if (UNIX)
-  add_custom_target(tags etags --members --declarations
-  `find ${CMAKE_CURRENT_SOURCE_DIR}/src
-   -name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or -name \\*.h -or -name \\*.c -or
-   -name \\*.f`)
-  add_custom_target(etags DEPENDS tags)
+  add_custom_target(etags etags --members --declarations
+    `find ${CMAKE_CURRENT_SOURCE_DIR}/src
+          ${CMAKE_CURRENT_BINARY_DIR}/src
+          -name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or
+          -name \\*.h -or -name \\*.c`)
 endif (UNIX)
 
 ############################################################
 # "make cscope" target
 ############################################################
 if (UNIX)
-  add_custom_target(cscope find ${CMAKE_CURRENT_SOURCE_DIR}
-  ( -name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or
-    -name \\*.h -or -name \\*.c -or -name \\*.f )
-  -exec echo \"{}\" \; > cscope.files && cscope -q -b VERBATIM)
+  add_custom_target(cscope
+    find ${CMAKE_CURRENT_SOURCE_DIR}/src
+         ${CMAKE_CURRENT_BINARY_DIR}/src
+         -name \\*.cc -or -name \\*.hh -or -name \\*.cpp -or
+         -name \\*.h -or -name \\*.c
+    > cscope.files && cscope -q -b)
 endif (UNIX)
 
 ############################################################
@@ -898,11 +902,12 @@ endif (UNIX)
 # "make docs" target
 ############################################################
 if (UNIX)
-  set(DOCS_BUILD_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/build/docs)
+  set(DOCS_BUILD_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/docs)
   add_custom_command(
     OUTPUT ${DOCS_BUILD_DIRECTORY}
     # We want the docs output HTML to go in a docs/ subdir of the output dir
-    COMMAND docs/support/scripts/make_docs.sh)
+    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/docs/support/scripts/make_docs.sh
+            --build_root ${CMAKE_CURRENT_BINARY_DIR})
   add_custom_target(docs
     DEPENDS ${DOCS_BUILD_DIRECTORY})
 endif (UNIX)

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/README.adoc
----------------------------------------------------------------------
diff --git a/README.adoc b/README.adoc
index c24a731..cfd73de 100644
--- a/README.adoc
+++ b/README.adoc
@@ -21,6 +21,17 @@
 Follow the steps in the http://getkudu.io/docs/installation.html#_build_from_source[documentation]
 to build and install Kudu from source
 
+=== Building Kudu out of tree
+
+A single Kudu source tree may be used for multiple builds, each with its
+own build directory. Build directories may be placed anywhere in the
+filesystem with the exception of the root directory of the source tree. The
+Kudu build is invoked with a working directory of the build directory
+itself, so you must ensure it exists (i.e. create it with _mkdir -p_).
+
+The rest of this document assumes the build directory
+_<root directory of kudu source tree>/build/debug_.
+
 === Automatic rebuilding of dependencies
 
 The script `thirdparty/build-if-necessary.sh` is invoked by cmake, so
@@ -32,7 +43,8 @@ To disable the automatic invocation of `build-if-necessary.sh`, set the
 
 [source,bash]
 ----
-$ NO_REBUILD_THIRDPARTY=1 cmake .
+$ cd build/debug
+$ NO_REBUILD_THIRDPARTY=1 cmake ../..
 ----
 
 This can be particularly useful when trying to run tools like `git bisect`
@@ -46,45 +58,48 @@ between two commits which may have different dependencies.
 # Add <root of kudu tree>/thirdparty/installed/bin to your $PATH
 # before other parts of $PATH that may contain cmake, such as /usr/bin
 # For example: "export PATH=$HOME/git/kudu/thirdparty/installed/bin:$PATH"
-# if using bash
-$ cmake .
+# if using bash.
+$ mkdir -p build/debug
+$ cd build/debug
+$ cmake ../..
 $ make -j8  # or whatever level of parallelism your machine can handle
 ----
 
 The build artifacts, including the test binaries, will be stored in
-_build/latest/_, which itself is a symlink to a build-type specific
-directory such as _build/debug_ or _build/release_.
+_build/debug/latest/_.
 
 To omit the Kudu unit tests during the build, add -DNO_TESTS=1 to the
 invocation of cmake. For example:
 
 [source,bash]
 ----
-$ cmake -DNO_TESTS=1 .
+$ cd build/debug
+$ cmake -DNO_TESTS=1 ../..
 ----
 
 == Running unit/functional tests
 
 To run the Kudu unit tests, you can use the `ctest` command from within the
-root of the Kudu repository:
+_build/debug_ directory:
 
 [source,bash]
 ----
+$ cd build/debug
 $ ctest -j8
 ----
 
 This command will report any tests that failed, and the test logs will be
-written to _build/test-logs_.
+written to _build/debug/test-logs_.
 
 Individual tests can be run by directly invoking the test binaries in
-_build/latest_. Since Kudu uses the Google C++ Test Framework (gtest),
+_build/debug/latest_. Since Kudu uses the Google C++ Test Framework (gtest),
 specific test cases can be run with gtest flags:
 
 [source,bash]
 ----
 # List all the tests within a test binary, then run a single test
-$ ./build/latest/tablet-test --gtest_list_tests
-$ ./build/latest/tablet-test --gtest_filter=TestTablet/9.TestFlush
+$ build/debug/latest/tablet-test --gtest_list_tests
+$ build/debug/latest/tablet-test --gtest_filter=TestTablet/9.TestFlush
 ----
 
 gtest also allows more complex filtering patterns. See the upstream
@@ -100,12 +115,13 @@ before pushing. To do so, you'll need to build using `clang`:
 
 [source,bash]
 ----
-$ rm -Rf CMakeCache.txt CMakeFiles/
-$ CC=$(pwd)/thirdparty/clang-toolchain/bin/clang \
-  CXX=$(pwd)/thirdparty/clang-toolchain/bin/clang++ \
-  cmake -DKUDU_USE_ASAN=1 .
+$ mkdir -p build/asan
+$ cd build/asan
+$ CC=../../thirdparty/clang-toolchain/bin/clang \
+  CXX=../../thirdparty/clang-toolchain/bin/clang++ \
+  cmake -DKUDU_USE_ASAN=1 ../..
 $ make -j8
-$ make test
+$ ctest -j8
 ----
 
 The tests will run significantly slower than without ASAN enabled, and if any
@@ -115,10 +131,11 @@ command like:
 
 [source,bash]
 ----
-$ build/latest/failing-test 2>&1 | thirdparty/asan_symbolize.py | c++filt | less
+$ cd build/asan
+$ ctest -R failing-test
 ----
 
-to get a proper symbolized stack trace.
+to run just the failed test.
 
 NOTE: For more information on AddressSanitizer, please see the
 http://clang.llvm.org/docs/AddressSanitizer.html[ASAN web page].
@@ -149,11 +166,12 @@ and aborts if it detects memory leaks in your program.
 
 [source,bash]
 ----
-$ rm -Rf CMakeCache.txt CMakeFiles/
-$ cmake .
-$ make -j
+$ mkdir -p build/leakcheck
+$ cd build/leakcheck
+$ cmake ../..
+$ make -j8
 $ # Note: LP_BIND_NOW=1 required below, see: https://code.google.com/p/gperftools/issues/detail?id=497
-$ PPROF_PATH=thirdparty/installed/bin/pprof HEAPCHECK=normal LD_BIND_NOW=1 ctest -j8
+$ PPROF_PATH=../../thirdparty/installed/bin/pprof HEAPCHECK=normal LD_BIND_NOW=1 ctest -j8
 ----
 
 NOTE: For more information on the heap checker, please see:
@@ -173,9 +191,10 @@ recompile, and run tests. For example:
 
 [source,bash]
 ----
-$ rm -Rf CMakeCache.txt CMakeFiles/
-$ CC=$(pwd)/thirdparty/clang-toolchain/bin/clang \
-    CXX=$(pwd)/thirdparty/clang-toolchain/bin/clang++ \
+$ mkdir -p build/tsan
+$ cd build/tsan
+$ CC=../../thirdparty/clang-toolchain/bin/clang \
+    CXX=../../thirdparty/clang-toolchain/bin/clang++ \
     cmake -DKUDU_USE_TSAN=1 .
 $ make -j8
 $ ctest -j8
@@ -185,7 +204,7 @@ $ ctest -j8
 [NOTE]
 ====
 Note that we rely on a list of runtime suppressions in _build-support/tsan-suppressions.txt_.
-If you simply run a unit test like _build/latest/foo-test_, you won't get these suppressions.
+If you simply run a unit test like _build/tsan/latest/foo-test_, you won't get these suppressions.
 Instead, use a command like:
 
 [source,bash]
@@ -193,7 +212,7 @@ Instead, use a command like:
 $ ctest -R foo-test
 ----
 
-...and then view the logs in _build/test-logs/_
+...and then view the logs in _build/tsan/test-logs/_
 
 In order for all of the suppressions to work, you need libraries with debug
 symbols installed, particularly for libstdc\+\+. On Ubuntu 13.10, the package
@@ -222,7 +241,9 @@ and use the following flags:
 
 [source,bash]
 ----
-$ cmake -DKUDU_GENERATE_COVERAGE=1 .
+$ mkdir -p build/coverage
+$ cd build/coverage
+$ cmake -DKUDU_GENERATE_COVERAGE=1 ../..
 $ make -j4
 $ ctest -j4
 ----
@@ -284,7 +305,7 @@ including Javadoc documentation, you may run the following command:
 
 [source,bash]
 ----
-$ ./docs/support/script/make_site.sh build/site # here, build/site is your desired output directory
+$ ./docs/support/script/make_site.sh
 ----
 
 This script will use your local Git repository to check out a shallow clone of
@@ -292,6 +313,7 @@ the 'gh-pages' branch and use `make_docs.sh` to generate the HTML documentation
 for the web site. It will also build the Javadoc documentation. These will be
 placed inside the checked-out web site, along with a tarball containing only
 the generated documentation (the _docs/_ and _apidocs/_ paths on the web site).
+Everything can be found in the _build/site_ subdirectory.
 
 You can proceed to commit the changes in the pages repository and send a code
 review for your changes. In the future, this step may be automated whenever
@@ -329,7 +351,7 @@ dynamic linking explicitly, run:
 
 [source,bash]
 ----
-$ cmake -DKUDU_LINK=dynamic .
+$ cmake -DKUDU_LINK=dynamic ../..
 ----
 
 Subsequent builds will create shared objects instead of archives and use them when
@@ -348,7 +370,7 @@ Eclipse can be used as an IDE for Kudu. To generate Eclipse project files, run:
 [source,bash]
 ----
 $ rm -rf CMakeCache.txt CMakeFiles/
-$ cmake -G "Eclipse CDT4 - Unix Makefiles" .
+$ cmake -G "Eclipse CDT4 - Unix Makefiles" ../..
 ----
 
 It's critical that _CMakeCache.txt_ be removed prior to running the generator,

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/build-support/jenkins/build-and-test.sh
----------------------------------------------------------------------
diff --git a/build-support/jenkins/build-and-test.sh b/build-support/jenkins/build-and-test.sh
index 2f688de..2844763 100755
--- a/build-support/jenkins/build-and-test.sh
+++ b/build-support/jenkins/build-and-test.sh
@@ -100,30 +100,27 @@ if [ ! -w "$TEST_TMPDIR" ]; then
   exit 1
 fi
 
-ROOT=$(cd $(dirname "$BASH_SOURCE")/../..; pwd)
-cd $ROOT
+SOURCE_ROOT=$(cd $(dirname "$BASH_SOURCE")/../..; pwd)
+BUILD_ROOT=$SOURCE_ROOT/build
+
+# Remove testing artifacts from the previous run before we do anything
+# else. Otherwise, if we fail during the "build" step, Jenkins will
+# archive the test logs from the previous run, thinking they came from
+# this run, and confuse us when we look at the failed build.
+rm -rf $BUILD_ROOT
+mkdir -p $BUILD_ROOT
 
 list_flaky_tests() {
   curl -s "http://$TEST_RESULT_SERVER/list_failed_tests?num_days=3&build_pattern=%25kudu-test%25"
   return $?
 }
 
-TEST_LOGDIR="$ROOT/build/test-logs"
-TEST_DEBUGDIR="$ROOT/build/test-debug"
-
-# Remove testing artifacts from the previous run before we do anything
-# else. Otherwise, if we fail during the "build" step, Jenkins will
-# archive the test logs from the previous run, thinking they came from
-# this run, and confuse us when we look at the failed build.
-rm -Rf Testing/Temporary
-rm -f build.log
-rm -Rf $TEST_LOGDIR
-rm -Rf $TEST_DEBUGDIR
-rm -rf CMakeCache.txt CMakeFiles src/kudu/*/CMakeFiles
+TEST_LOGDIR="$BUILD_ROOT/test-logs"
+TEST_DEBUGDIR="$BUILD_ROOT/test-debug"
 
 cleanup() {
   echo Cleaning up all build artifacts...
-  $ROOT/build-support/jenkins/post-build-clean.sh
+  $SOURCE_ROOT/build-support/jenkins/post-build-clean.sh
 }
 # If we're running inside Jenkins (the BUILD_ID is set), then install
 # an exit handler which will clean up all of our build results.
@@ -136,7 +133,7 @@ if [ -d "$TOOLCHAIN_DIR" ]; then
   PATH=$TOOLCHAIN_DIR/apache-maven-3.0/bin:$PATH
 fi
 
-$ROOT/build-support/enable_devtoolset.sh thirdparty/build-if-necessary.sh
+$SOURCE_ROOT/build-support/enable_devtoolset.sh thirdparty/build-if-necessary.sh
 
 THIRDPARTY_BIN=$(pwd)/thirdparty/installed/bin
 export PPROF_PATH=$THIRDPARTY_BIN/pprof
@@ -147,18 +144,24 @@ else
   CLANG=$(pwd)/thirdparty/clang-toolchain/bin/clang
 fi
 
+# Before running cmake below, clean out any errant cmake state from the source
+# tree. We need this to help transition into a world where out-of-tree builds
+# are required. Once that's done, the cleanup can be removed.
+rm -rf $SOURCE_ROOT/CMakeCache.txt $SOURCE_ROOT/CMakeFiles
+
 # Configure the build
 #
 # ASAN/TSAN can't build the Python bindings because the exported Kudu client
 # library (which the bindings depend on) is missing ASAN/TSAN symbols.
+cd $BUILD_ROOT
 if [ "$BUILD_TYPE" = "ASAN" ]; then
-  $ROOT/build-support/enable_devtoolset.sh \
-    "CC=$CLANG CXX=$CLANG++ $THIRDPARTY_BIN/cmake -DKUDU_USE_ASAN=1 -DKUDU_USE_UBSAN=1 ."
+  $SOURCE_ROOT/build-support/enable_devtoolset.sh \
+    "CC=$CLANG CXX=$CLANG++ $THIRDPARTY_BIN/cmake -DKUDU_USE_ASAN=1 -DKUDU_USE_UBSAN=1 $SOURCE_ROOT"
   BUILD_TYPE=fastdebug
   BUILD_PYTHON=0
 elif [ "$BUILD_TYPE" = "TSAN" ]; then
-  $ROOT/build-support/enable_devtoolset.sh \
-    "CC=$CLANG CXX=$CLANG++ $THIRDPARTY_BIN/cmake -DKUDU_USE_TSAN=1"
+  $SOURCE_ROOT/build-support/enable_devtoolset.sh \
+    "CC=$CLANG CXX=$CLANG++ $THIRDPARTY_BIN/cmake -DKUDU_USE_TSAN=1 $SOURCE_ROOT"
   BUILD_TYPE=fastdebug
   EXTRA_TEST_FLAGS="$EXTRA_TEST_FLAGS -LE no_tsan"
   BUILD_PYTHON=0
@@ -170,7 +173,7 @@ elif [ "$BUILD_TYPE" = "LEAKCHECK" ]; then
 elif [ "$BUILD_TYPE" = "COVERAGE" ]; then
   DO_COVERAGE=1
   BUILD_TYPE=debug
-  $ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake -DKUDU_GENERATE_COVERAGE=1 ."
+  $SOURCE_ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake -DKUDU_GENERATE_COVERAGE=1 $SOURCE_ROOT"
   # Reset coverage info from previous runs
   find src -name \*.gcda -o -name \*.gcno -exec rm {} \;
 elif [ "$BUILD_TYPE" = "LINT" ]; then
@@ -179,7 +182,7 @@ elif [ "$BUILD_TYPE" = "LINT" ]; then
   mkdir -p Testing/Temporary
   mkdir -p $TEST_LOGDIR
 
-  $ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake ."
+  $SOURCE_ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake $SOURCE_ROOT"
   make lint | tee $TEST_LOGDIR/lint.log
   exit $?
 fi
@@ -193,7 +196,7 @@ fi
 # list of tests to ignore
 if [ "$KUDU_FLAKY_TEST_ATTEMPTS" -gt 1 ]; then
   echo Fetching flaky test list...
-  export KUDU_FLAKY_TEST_LIST=$ROOT/build/flaky-tests.txt
+  export KUDU_FLAKY_TEST_LIST=$BUILD_ROOT/flaky-tests.txt
   mkdir -p $(dirname $KUDU_FLAKY_TEST_LIST)
   echo -n > $KUDU_FLAKY_TEST_LIST
     if [ -n "$TEST_RESULT_SERVER" ] && \
@@ -207,10 +210,9 @@ if [ "$KUDU_FLAKY_TEST_ATTEMPTS" -gt 1 ]; then
   fi
 fi
 
-$ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE}"
+$SOURCE_ROOT/build-support/enable_devtoolset.sh "$THIRDPARTY_BIN/cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} $SOURCE_ROOT"
 
 # our tests leave lots of data lying around, clean up before we run
-make clean
 if [ -d "$TEST_TMPDIR" ]; then
   rm -Rf $TEST_TMPDIR/*
 fi
@@ -256,7 +258,7 @@ if [ $EXIT_STATUS != 0 ]; then
     if [ ! -f "$GTEST_XMLFILE" ]; then
       echo "JUnit report missing:" \
            "generating fake JUnit report file from $GTEST_OUTFILE and saving it to $GTEST_XMLFILE"
-      zcat $GTEST_OUTFILE | $ROOT/build-support/parse_test_failure.py -x > $GTEST_XMLFILE
+      zcat $GTEST_OUTFILE | $SOURCE_ROOT/build-support/parse_test_failure.py -x > $GTEST_XMLFILE
     fi
   done
 fi
@@ -283,8 +285,8 @@ if [ "$BUILD_JAVA" == "1" ]; then
   # Make sure we use JDK7
   export JAVA_HOME=$JAVA7_HOME
   export PATH=$JAVA_HOME/bin:$PATH
-  pushd java
-  export TSAN_OPTIONS="$TSAN_OPTIONS suppressions=$ROOT/build-support/tsan-suppressions.txt history_size=7"
+  pushd $SOURCE_ROOT/java
+  export TSAN_OPTIONS="$TSAN_OPTIONS suppressions=$SOURCE_ROOT/build-support/tsan-suppressions.txt history_size=7"
   set -x
   VALIDATE_CSD_FLAG=""
   if [ "$VALIDATE_CSD" == "1" ]; then
@@ -315,13 +317,14 @@ fi
 if [ "$BUILD_PYTHON" == "1" ]; then
   # Failing to compile the Python client should result in a build failure
   set -e
-  export KUDU_HOME=$(pwd)
-  pushd python
+  export KUDU_HOME=$SOURCE_ROOT
+  export KUDU_BUILD=$BUILD_ROOT
+  pushd $SOURCE_ROOT/python
 
   # Create a sane test environment
-  rm -Rf test_environment
-  virtualenv test_environment
-  source test_environment/bin/activate
+  rm -Rf $KUDU_BUILD/py_env
+  virtualenv $KUDU_BUILD/py_env
+  source $KUDU_BUILD/py_env/bin/activate
   pip install --upgrade pip
   CC=$CLANG CXX=$CLANG++ pip install --disable-pip-version-check -r requirements.txt
 
@@ -329,8 +332,8 @@ if [ "$BUILD_PYTHON" == "1" ]; then
   CC=$CLANG CXX=$CLANG++ python setup.py build_ext
   set +e
   python setup.py test \
-    --addopts="kudu --junit-xml=$KUDU_HOME/build/test-logs/python_client.xml" \
-    2> $KUDU_HOME/build/test-logs/python_client.log || EXIT_STATUS=$?
+    --addopts="kudu --junit-xml=$KUDU_BUILD/test-logs/python_client.xml" \
+    2> $KUDU_BUILD/test-logs/python_client.log || EXIT_STATUS=$?
 fi
 
 set -e

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/build-support/run-test.sh
----------------------------------------------------------------------
diff --git a/build-support/run-test.sh b/build-support/run-test.sh
index 06ed8e9..605a325 100755
--- a/build-support/run-test.sh
+++ b/build-support/run-test.sh
@@ -32,18 +32,24 @@
 # If KUDU_REPORT_TEST_RESULTS is non-zero, then tests are reported to the
 # central test server.
 
-ROOT=$(cd $(dirname $BASH_SOURCE)/..; pwd)
+# Path to the test executable or script to be run.
+TEST_PATH=$1
 
-TEST_LOGDIR=$ROOT/build/test-logs
+# Path to the root source directory. This script is expected to live within it.
+SOURCE_ROOT=$(dirname "$BASH_SOURCE")/..
+
+# Path to the root build directory. The test path is expected to be within it.
+BUILD_ROOT=$(dirname "$TEST_PATH")/..
+
+TEST_LOGDIR=$BUILD_ROOT/test-logs
 mkdir -p $TEST_LOGDIR
 
-TEST_DEBUGDIR=$ROOT/build/test-debug
+TEST_DEBUGDIR=$BUILD_ROOT/test-debug
 mkdir -p $TEST_DEBUGDIR
 
-TEST_DIRNAME=$(cd $(dirname $1); pwd)
-TEST_FILENAME=$(basename $1)
+TEST_DIRNAME=$(cd $(dirname $TEST_PATH); pwd)
+TEST_FILENAME=$(basename $TEST_PATH)
 shift
-TEST_EXECUTABLE="$TEST_DIRNAME/$TEST_FILENAME"
 TEST_NAME=$(echo $TEST_FILENAME | perl -pe 's/\..+?$//') # Remove path and extension (if any).
 
 # Determine whether the test is a known flaky by comparing against the user-specified
@@ -65,7 +71,7 @@ fi
 
 
 # We run each test in its own subdir to avoid core file related races.
-TEST_WORKDIR=$ROOT/build/test-work/$TEST_NAME
+TEST_WORKDIR=$BUILD_ROOT/test-work/$TEST_NAME
 mkdir -p $TEST_WORKDIR
 pushd $TEST_WORKDIR >/dev/null || exit 1
 rm -f *
@@ -90,7 +96,7 @@ fi
 # Suppressions require symbolization. We'll default to using the symbolizer in
 # thirdparty.
 if [ -z "$ASAN_SYMBOLIZER_PATH" ]; then
-  export ASAN_SYMBOLIZER_PATH=$ROOT/thirdparty/clang-toolchain/bin/llvm-symbolizer
+  export ASAN_SYMBOLIZER_PATH=$SOURCE_ROOT/thirdparty/clang-toolchain/bin/llvm-symbolizer
 fi
 
 # Configure TSAN (ignored if this isn't a TSAN build).
@@ -101,7 +107,7 @@ fi
 # 2. Many unit tests report lock-order-inversion warnings; they should be
 #    fixed before reenabling the detector.
 TSAN_OPTIONS="$TSAN_OPTIONS detect_deadlocks=0"
-TSAN_OPTIONS="$TSAN_OPTIONS suppressions=$ROOT/build-support/tsan-suppressions.txt"
+TSAN_OPTIONS="$TSAN_OPTIONS suppressions=$SOURCE_ROOT/build-support/tsan-suppressions.txt"
 TSAN_OPTIONS="$TSAN_OPTIONS history_size=7"
 TSAN_OPTIONS="$TSAN_OPTIONS external_symbolizer_path=$ASAN_SYMBOLIZER_PATH"
 export TSAN_OPTIONS
@@ -112,7 +118,7 @@ ASAN_OPTIONS="$ASAN_OPTIONS detect_leaks=1"
 export ASAN_OPTIONS
 
 # Set up suppressions for LeakSanitizer
-LSAN_OPTIONS="$LSAN_OPTIONS suppressions=$ROOT/build-support/lsan-suppressions.txt"
+LSAN_OPTIONS="$LSAN_OPTIONS suppressions=$SOURCE_ROOT/build-support/lsan-suppressions.txt"
 export LSAN_OPTIONS
 
 # Set a 15-minute timeout for tests run via 'make test'.
@@ -142,8 +148,8 @@ for ATTEMPT_NUMBER in $(seq 1 $TEST_EXECUTION_ATTEMPTS) ; do
 
   echo "Running $TEST_NAME, redirecting output into $LOGFILE" \
     "(attempt ${ATTEMPT_NUMBER}/$TEST_EXECUTION_ATTEMPTS)"
-  $TEST_EXECUTABLE "$@" --test_timeout_after $KUDU_TEST_TIMEOUT 2>&1 \
-    | $ROOT/build-support/stacktrace_addr2line.pl $TEST_EXECUTABLE \
+  $TEST_PATH "$@" --test_timeout_after $KUDU_TEST_TIMEOUT 2>&1 \
+    | $SOURCE_ROOT/build-support/stacktrace_addr2line.pl $TEST_PATH \
     | $pipe_cmd > $LOGFILE
   STATUS=$?
 
@@ -183,7 +189,7 @@ for ATTEMPT_NUMBER in $(seq 1 $TEST_EXECUTION_ATTEMPTS) ; do
 
   if [ -n "$KUDU_REPORT_TEST_RESULTS" ]; then
     echo Reporting results
-    $ROOT/build-support/report-test.sh "$TEST_EXECUTABLE" "$LOGFILE" "$STATUS" &
+    $SOURCE_ROOT/build-support/report-test.sh "$TEST_PATH" "$LOGFILE" "$STATUS" &
 
     # On success, we'll do "best effort" reporting, and disown the subprocess.
     # On failure, we want to upload the failed test log. So, in that case,
@@ -223,12 +229,12 @@ fi
 COREFILES=$(ls | grep ^core)
 if [ -n "$COREFILES" ]; then
   echo Found core dump. Saving executable and core files.
-  gzip < $TEST_EXECUTABLE > "$TEST_DEBUGDIR/$TEST_NAME.gz" || exit $?
+  gzip < $TEST_PATH > "$TEST_DEBUGDIR/$TEST_NAME.gz" || exit $?
   for COREFILE in $COREFILES; do
     gzip < $COREFILE > "$TEST_DEBUGDIR/$TEST_NAME.$COREFILE.gz" || exit $?
   done
   # Pull in any .so files as well.
-  for LIB in $(ldd $TEST_EXECUTABLE | grep $ROOT | awk '{print $3}'); do
+  for LIB in $(ldd $TEST_PATH | grep $BUILD_ROOT | awk '{print $3}'); do
     LIB_NAME=$(basename $LIB)
     gzip < $LIB > "$TEST_DEBUGDIR/$LIB_NAME.gz" || exit $?
   done

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/cmake_modules/FindKRPC.cmake
----------------------------------------------------------------------
diff --git a/cmake_modules/FindKRPC.cmake b/cmake_modules/FindKRPC.cmake
index 31e0d86..996d9f5 100644
--- a/cmake_modules/FindKRPC.cmake
+++ b/cmake_modules/FindKRPC.cmake
@@ -77,10 +77,6 @@ function(KRPC_GENERATE SRCS HDRS TGTS)
     list(APPEND ${SRCS} "${PROTO_CC_OUT}" "${SERVICE_CC}" "${PROXY_CC}")
     list(APPEND ${HDRS} "${PROTO_H_OUT}" "${SERVICE_H}" "${PROXY_H}")
 
-    if(NOT EXISTS ${PROTO_DST_ROOT}/${FIL_PT})
-        file(MAKE_DIRECTORY ${PROTO_DST_ROOT}/${FIL_PT})
-    endif()
-
     add_custom_command(
       OUTPUT "${SERVICE_CC}" "${SERVICE_H}" "${PROXY_CC}" "${PROXY_H}"
              "${PROTO_CC_OUT}" "${PROTO_H_OUT}"

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/cmake_modules/FindProtobuf.cmake
----------------------------------------------------------------------
diff --git a/cmake_modules/FindProtobuf.cmake b/cmake_modules/FindProtobuf.cmake
index e5401de..108d68c 100644
--- a/cmake_modules/FindProtobuf.cmake
+++ b/cmake_modules/FindProtobuf.cmake
@@ -113,10 +113,6 @@ function(PROTOBUF_GENERATE_CPP SRCS HDRS TGTS)
     list(APPEND ${SRCS} "${PROTO_CC_OUT}")
     list(APPEND ${HDRS} "${PROTO_H_OUT}")
 
-    if(NOT EXISTS ${PROTO_DST_ROOT}/${FIL_PT})
-        file(MAKE_DIRECTORY ${PROTO_DST_ROOT}/${FIL_PT})
-    endif()
-
     add_custom_command(
       OUTPUT "${PROTO_CC_OUT}" "${PROTO_H_OUT}"
       COMMAND  ${PROTOBUF_PROTOC_EXECUTABLE}

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/docs/installation.adoc
----------------------------------------------------------------------
diff --git a/docs/installation.adoc b/docs/installation.adoc
index 4964d27..6f5536e 100644
--- a/docs/installation.adoc
+++ b/docs/installation.adoc
@@ -230,13 +230,20 @@ $ cd kudu
 $ thirdparty/build-if-necessary.sh
 ----
 
-. Build Kudu, using the utilities installed in the previous step. Edit the install
-prefix to the location where you would like the Kudu binaries, libraries, and headers
-installed during the `make install` step. The default value is `/usr/local/`.
+. Build Kudu, using the utilities installed in the previous step. Choose a build
+directory for the intermediate output, which can be anywhere in your filesystem
+except for the `kudu` directory itself. Edit the install prefix to the location
+where you would like the Kudu binaries, libraries, and headers installed during
+the `make install` step. The default value is `/usr/local/`.
 +
 [source,bash]
 ----
-thirdparty/installed/bin/cmake . -DCMAKE_BUILD_TYPE=release -DCMAKE_INSTALL_PREFIX=/opt/kudu
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake \
+  -DCMAKE_BUILD_TYPE=release \
+  -DCMAKE_INSTALL_PREFIX=/opt/kudu \
+  ..
 make -j4
 ----
 [[build_install_kudu]]
@@ -269,7 +276,11 @@ sudo yum -y install boost-static boost-devel openssl-devel cyrus-sasl-devel \
   cyrus-sasl-plain patch pkg-config make rsync vim-common gdb
 cd kudu
 thirdparty/build-if-necessary.sh
-thirdparty/installed/bin/cmake . -DCMAKE_BUILD_TYPE=release
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake \
+  -DCMAKE_BUILD_TYPE=release \
+  ..
 make -j4
 make install
 ----
@@ -307,13 +318,30 @@ $ cd kudu
 $ thirdparty/build-if-necessary.sh
 ----
 
-. Build Kudu.
+. Build Kudu, using the utilities installed in the previous step. Choose a build
+directory for the intermediate output, which can be anywhere in your filesystem
+except for the `kudu` directory itself. Edit the install prefix to the location
+where you would like the Kudu binaries, libraries, and headers installed during
+the `make install` step. The default value is `/usr/local/`.
 +
 [source,bash]
 ----
-thirdparty/installed/bin/cmake . -DCMAKE_BUILD_TYPE=release
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake \
+  -DCMAKE_BUILD_TYPE=release \
+  -DCMAKE_INSTALL_PREFIX=/opt/kudu \
+  ..
 make -j4
 ----
+[[build_install_kudu]]
+. Optional: Install Kudu binaries, libraries, and headers.
+If you do not specify a `DESTDIR`, `/usr/local/` is the default.
++
+[source,bash]
+----
+sudo make DESTDIR=/opt/kudu install
+----
 
 . Optional: Build the documentation. NOTE: This command builds local documentation that
 is not appropriate for uploading to the Kudu website.
@@ -338,7 +366,11 @@ sudo apt-get -y install git autoconf automake libboost-thread-dev curl gcc g++ \
 git clone http://github.com/cloudera/kudu
 cd kudu
 thirdparty/build-if-necessary.sh
-thirdparty/installed/bin/cmake . -DCMAKE_BUILD_TYPE=release
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake \
+  -DCMAKE_BUILD_TYPE=release \
+  ..
 make -j4
 make install
 ----
@@ -387,11 +419,14 @@ $ cd kudu
 $ thirdparty/build-if-necessary.sh
 ----
 
-. Build Kudu.
+. Build Kudu. Choose a build directory for the intermediate output, which can be
+anywhere in your filesystem except for the `kudu` directory itself.
 +
 [source,bash]
 ----
-thirdparty/installed/bin/cmake .
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake ..
 make -j4
 ----
 
@@ -410,7 +445,9 @@ brew link -f openssl
 git clone http://github.com/cloudera/kudu
 cd kudu
 thirdparty/build-if-necessary.sh
-thirdparty/installed/bin/cmake .
+mkdir -p build
+cd build
+../thirdparty/installed/bin/cmake ..
 make -j4
 ----
 ====

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/docs/support/scripts/make_docs.sh
----------------------------------------------------------------------
diff --git a/docs/support/scripts/make_docs.sh b/docs/support/scripts/make_docs.sh
index a41fcdc..33f715d 100755
--- a/docs/support/scripts/make_docs.sh
+++ b/docs/support/scripts/make_docs.sh
@@ -31,50 +31,9 @@
 set -e
 
 usage() {
-  echo usage: "$0 [--site <path to gh-pages checkout>]"
+  echo usage: "$0 --build_root <path to build root> [--site <path to gh-pages checkout>]"
 }
 
-ROOT=$(cd $(dirname $0)/../../..; pwd)
-
-GEN_DOC_DIR=$ROOT/build/gen-docs
-OUTPUT_DIR=$ROOT/build/docs
-
-if ! which ruby > /dev/null; then
-  echo "ruby must be installed in order to build the docs."
-  echo 1
-fi
-
-DOCS_SCRIPTS="$ROOT/docs/support/scripts"
-
-# We must set GEM_PATH because bundler depends on it to find its own libraries.
-export GEM_PATH="$DOCS_SCRIPTS/.gem"
-echo GEM_PATH="$DOCS_SCRIPTS/.gem"
-
-export PATH="$GEM_PATH/bin:$PATH"
-echo PATH="$GEM_PATH/bin:$PATH"
-
-BUNDLE="$GEM_PATH/bin/bundle"
-
-echo "Locally Installing ruby gems needed to build docs."
-if [ ! -x "$BUNDLE" ]; then
-  set -x
-  gem install --no-ri --no-rdoc -q --install-dir "$GEM_PATH" bundler
-  set +x
-fi
-
-set -x
-cd "$DOCS_SCRIPTS"
-"$BUNDLE" install --no-color --path "$GEM_PATH"
-set +x
-
-# We need the xsltproc package.
-for requirement in "xsltproc"; do
-  if ! which $requirement > /dev/null; then
-    echo "$requirement is required, but cannot be found. Make sure it is in your path."
-    exit 1
-  fi
-done
-
 while [[ $# > 0 ]] ; do
     arg=$1
     case $arg in
@@ -82,6 +41,11 @@ while [[ $# > 0 ]] ; do
         usage
         exit 1
         ;;
+      --build_root)
+        BUILD_ROOT=$2
+        shift
+        shift
+        ;;
       --site|-s)
         SITE=$2
         if [ -z "$SITE" ]; then
@@ -108,6 +72,56 @@ while [[ $# > 0 ]] ; do
     esac
 done
 
+if [ -z "$BUILD_ROOT" ]; then
+  usage
+  exit 1
+fi
+
+if [ -z "$SITE" ]; then
+  OUTPUT_DIR=$BUILD_ROOT/docs
+fi
+
+GEN_DOC_DIR=$BUILD_ROOT/gen-docs
+SOURCE_ROOT=$(cd $(dirname $0)/../../..; pwd)
+
+if ! which ruby > /dev/null; then
+  echo "ruby must be installed in order to build the docs."
+  echo 1
+fi
+
+DOCS_SCRIPTS="$SOURCE_ROOT/docs/support/scripts"
+
+# We must set GEM_PATH because bundler depends on it to find its own libraries.
+export GEM_PATH="$BUILD_ROOT/gems"
+echo GEM_PATH=$GEM_PATH
+
+export PATH="$GEM_PATH/bin:$PATH"
+echo PATH="$GEM_PATH/bin:$PATH"
+
+BUNDLE="$GEM_PATH/bin/bundle"
+
+echo "Locally installing ruby gems needed to build docs."
+if [ ! -x "$BUNDLE" ]; then
+  set -x
+  gem install --no-ri --no-rdoc -q --install-dir "$GEM_PATH" bundler
+  set +x
+fi
+
+set -x
+cd "$BUILD_ROOT"
+cp $DOCS_SCRIPTS/Gemfile .
+cp $DOCS_SCRIPTS/Gemfile.lock .
+$BUNDLE install --no-color --path "$GEM_PATH"
+set +x
+
+# We need the xsltproc package.
+for requirement in "xsltproc"; do
+  if ! which $requirement > /dev/null; then
+    echo "$requirement is required, but cannot be found. Make sure it is in your path."
+    exit 1
+  fi
+done
+
 mkdir -p "$OUTPUT_DIR" "$GEN_DOC_DIR"
 
 # Create config flag references for each of the binaries below
@@ -115,7 +129,7 @@ binaries=("kudu-master" \
           "kudu-tserver")
 
 for binary in ${binaries[@]}; do
-  echo "Running $(basename $binary) --helpxml"
+  echo "Running $binary --helpxml"
 
   (
     # Reset environment to avoid affecting the default flag values.
@@ -126,7 +140,7 @@ for binary in ${binaries[@]}; do
 
     # Create the XML file.
     # This command exits with a nonzero value.
-    $ROOT/build/latest/$binary --helpxml > ${GEN_DOC_DIR}/$(basename $binary).xml || true
+    $BUILD_ROOT/latest/$binary --helpxml > ${GEN_DOC_DIR}/$(basename $binary).xml || true
   )
 
   # Create the supported config reference
@@ -134,7 +148,7 @@ for binary in ${binaries[@]}; do
     --stringparam binary $binary \
     --stringparam support-level stable \
     -o $GEN_DOC_DIR/${binary}_configuration_reference.adoc \
-      $ROOT/docs/support/xsl/gflags_to_asciidoc.xsl \
+      $SOURCE_ROOT/docs/support/xsl/gflags_to_asciidoc.xsl \
     ${GEN_DOC_DIR}/$binary.xml
   INCLUSIONS_SUPPORTED+="include::${binary}_configuration_reference.adoc[leveloffset=+1]\n"
 
@@ -143,29 +157,29 @@ for binary in ${binaries[@]}; do
     --stringparam binary $binary \
     --stringparam support-level unsupported \
     -o $GEN_DOC_DIR/${binary}_configuration_reference_unsupported.adoc \
-      $ROOT/docs/support/xsl/gflags_to_asciidoc.xsl \
+      $SOURCE_ROOT/docs/support/xsl/gflags_to_asciidoc.xsl \
     ${GEN_DOC_DIR}/$binary.xml
   INCLUSIONS_UNSUPPORTED+="include::${binary}_configuration_reference_unsupported.adoc[leveloffset=+1]\n"
 done
 
 # Add the includes to the configuration reference files, replacing the template lines
-cp $ROOT/docs/configuration_reference* $GEN_DOC_DIR/
+cp $SOURCE_ROOT/docs/configuration_reference* $GEN_DOC_DIR/
 sed -i "s#@@CONFIGURATION_REFERENCE@@#${INCLUSIONS_SUPPORTED}#" ${GEN_DOC_DIR}/configuration_reference.adoc
 sed -i "s#@@CONFIGURATION_REFERENCE@@#${INCLUSIONS_UNSUPPORTED}#" ${GEN_DOC_DIR}/configuration_reference_unsupported.adoc
 
 # If we're generating the web site, pass the template which causes us
 # to generate Jekyll templates instead of full HTML.
 if [ -n "$SITE" ]; then
-    TEMPLATE_FLAG="-T $ROOT/docs/support/jekyll-templates"
+    TEMPLATE_FLAG="-T $SOURCE_ROOT/docs/support/jekyll-templates"
 else
     TEMPLATE_FLAG=""
 fi
 
 bundle exec asciidoctor -d book $TEMPLATE_FLAG \
-    $ROOT/docs/*.adoc ${GEN_DOC_DIR}/*.adoc -D "$OUTPUT_DIR"
+    $SOURCE_ROOT/docs/*.adoc ${GEN_DOC_DIR}/*.adoc -D "$OUTPUT_DIR"
 
 mkdir -p "$OUTPUT_DIR/images"
-cp $ROOT/docs/images/* "$OUTPUT_DIR/images/"
+cp $SOURCE_ROOT/docs/images/* "$OUTPUT_DIR/images/"
 
 
 echo
@@ -192,4 +206,3 @@ if [ -n "$SITE" ] && [ -z "$NO_JEKYLL" ]; then
   echo $BASE_URL/index.html
   echo ----------------------
 fi
-

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/docs/support/scripts/make_site.sh
----------------------------------------------------------------------
diff --git a/docs/support/scripts/make_site.sh b/docs/support/scripts/make_site.sh
index bde72d2..e51b6f9 100755
--- a/docs/support/scripts/make_site.sh
+++ b/docs/support/scripts/make_site.sh
@@ -20,47 +20,34 @@
 #
 # This script generates site documentation and Javadocs.
 #
-# Usage: make_site.sh <output_dir>
+# Usage: make_site.sh
 ########################################################################
 set -e
 
-REL_OUTPUT_DIR=$1
-if [ -z "$REL_OUTPUT_DIR" ]; then
-  echo "usage: $0 <output_dir>"
-  exit 1
-fi
-
-# Ensure a clean build.
-mkdir -p "$REL_OUTPUT_DIR"
-ABS_OUTPUT_DIR=$(cd "$REL_OUTPUT_DIR"; pwd)
-SITE_OUTPUT_DIR="$ABS_OUTPUT_DIR/kudu-site"
-if [ -d "$SITE_OUTPUT_DIR" ]; then
-  echo "Error: Please remove the old site directory before running this script: $SITE_OUTPUT_DIR"
-  exit 1
-fi
-mkdir "$SITE_OUTPUT_DIR"
-
-ROOT=$(cd $(dirname $0)/../../..; pwd)
+SOURCE_ROOT=$(cd $(dirname $0)/../../..; pwd)
+BUILD_ROOT="$SOURCE_ROOT/build"
+SITE_OUTPUT_DIR="$BUILD_ROOT/site"
 set -x
 
-cd "$ROOT"
+cd "$SOURCE_ROOT"
 
 # Build Kudu thirdparty
-$ROOT/build-support/enable_devtoolset.sh ./thirdparty/build-if-necessary.sh
+$SOURCE_ROOT/build-support/enable_devtoolset.sh $SOURCE_ROOT/thirdparty/build-if-necessary.sh
 echo "Successfully built third-party dependencies."
 
 # Build the binaries so we can auto-generate the command-line references
-rm -rf CMakeCache.txt CMakeFiles
-$ROOT/build-support/enable_devtoolset.sh ./thirdparty/installed/bin/cmake -DNO_TESTS=1 .
+rm -rf "$BUILD_ROOT"
+mkdir -p "$BUILD_ROOT"
+cd "$BUILD_ROOT"
+$SOURCE_ROOT/build-support/enable_devtoolset.sh $SOURCE_ROOT/thirdparty/installed/bin/cmake -DNO_TESTS=1 $SOURCE_ROOT
 make -j$(getconf _NPROCESSORS_ONLN)
-rm -rf CMakeCache.txt CMakeFiles
 
 # Check out the gh-pages repo into $SITE_OUTPUT_DIR
-git clone -q $(git config --get remote.origin.url) --reference $(pwd) -b gh-pages --depth 1 "$SITE_OUTPUT_DIR"
+git clone -q $(git config --get remote.origin.url) --reference $SOURCE_ROOT -b gh-pages --depth 1 "$SITE_OUTPUT_DIR"
 
 # Build the docs using the styles from the Jekyll site
 rm -Rf "$SITE_OUTPUT_DIR/docs"
-./docs/support/scripts/make_docs.sh --site "$SITE_OUTPUT_DIR"
+$SOURCE_ROOT/docs/support/scripts/make_docs.sh --build_root $BUILD_ROOT --site "$SITE_OUTPUT_DIR"
 if [ -f "$SITE_OUTPUT_DIR/docs/index.html" ]; then
   echo "Successfully built docs."
 else
@@ -68,11 +55,11 @@ else
   exit 1
 fi
 
-cd "$ROOT/java"
+cd "$SOURCE_ROOT/java"
 mvn clean install -DskipTests
 mvn clean javadoc:aggregate
 
-if [ -f "$ROOT/java/target/site/apidocs/index.html" ]; then
+if [ -f "$SOURCE_ROOT/java/target/site/apidocs/index.html" ]; then
   echo "Successfully built Javadocs."
 else
   echo "Javadocs failed to build."
@@ -80,7 +67,7 @@ else
 fi
 
 rm -Rf "$SITE_OUTPUT_DIR/apidocs"
-cp -au "$ROOT/java/target/site/apidocs" "$SITE_OUTPUT_DIR/"
+cp -au "$SOURCE_ROOT/java/target/site/apidocs" "$SITE_OUTPUT_DIR/"
 
 cd "$SITE_OUTPUT_DIR"
 SITE_ARCHIVE="$SITE_OUTPUT_DIR/website_archive.zip"

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/python/kudu/tests/common.py
----------------------------------------------------------------------
diff --git a/python/kudu/tests/common.py b/python/kudu/tests/common.py
index a944d7d..07d97e2 100644
--- a/python/kudu/tests/common.py
+++ b/python/kudu/tests/common.py
@@ -42,7 +42,7 @@ class KuduTestBase(object):
     @classmethod
     def start_cluster(cls):
         local_path = tempfile.mkdtemp(dir=os.getenv("TEST_TMPDIR", None))
-        bin_path = "{0}/build/latest".format(os.getenv("KUDU_HOME"))
+        bin_path = "{0}/latest".format(os.getenv("KUDU_BUILD"))
 
         os.makedirs("{0}/master/".format(local_path))
         os.makedirs("{0}/master/data".format(local_path))

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/python/setup.py
----------------------------------------------------------------------
diff --git a/python/setup.py b/python/setup.py
index 4a9828f..2c076b2 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -69,13 +69,11 @@ class clean(_clean):
 
 # If we're in the context of the Kudu git repository, build against the
 # latest in-tree build artifacts
-if ('KUDU_HOME' in os.environ and
-        os.path.exists(os.path.join(os.environ['KUDU_HOME'],
-                                    "build/latest"))):
+if 'KUDU_HOME' in os.environ and 'KUDU_BUILD' in os.environ:
     sys.stderr.write("Building from in-tree build artifacts\n")
-    kudu_include_dir = os.path.join(os.environ['KUDU_HOME'], 'src')
-    kudu_lib_dir = os.path.join(os.environ['KUDU_HOME'],
-                                'build/latest/exported')
+    kudu_include_dirs = [os.path.join(os.environ['KUDU_HOME'], 'src')]
+    kudu_include_dirs.append(os.path.join(os.environ['KUDU_BUILD'], 'src'))
+    kudu_lib_dir = os.path.join(os.environ['KUDU_BUILD'], 'latest/exported')
 else:
     if os.path.exists("/usr/local/include/kudu"):
         prefix = "/usr/local"
@@ -85,10 +83,10 @@ else:
         sys.stderr.write("Cannot find installed kudu client.\n")
         sys.exit(1)
     sys.stderr.write("Building from system prefix {0}\n".format(prefix))
-    kudu_include_dir = prefix + "/include"
+    kudu_include_dirs = [prefix + "/include"]
     kudu_lib_dir = prefix + "/lib"
 
-INCLUDE_PATHS = [kudu_include_dir]
+INCLUDE_PATHS = kudu_include_dirs
 LIBRARY_DIRS = [kudu_lib_dir]
 RT_LIBRARY_DIRS = LIBRARY_DIRS
 

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/client/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/client/CMakeLists.txt b/src/kudu/client/CMakeLists.txt
index e782aa2..3299e22 100644
--- a/src/kudu/client/CMakeLists.txt
+++ b/src/kudu/client/CMakeLists.txt
@@ -136,7 +136,7 @@ set_target_properties(kudu_client_exported
 # Generate kudu_export.h.
 generate_export_header(kudu_client_exported
   BASE_NAME kudu
-  EXPORT_FILE_NAME ${CMAKE_SOURCE_DIR}/src/kudu/util/kudu_export.h)
+  EXPORT_FILE_NAME ${CMAKE_BINARY_DIR}/src/kudu/util/kudu_export.h)
 
 # "make install" invocations to generate a directory tree containing the
 # exported client library and all of its headers.
@@ -169,7 +169,7 @@ install(FILES
 
 # Headers: util
 install(FILES
-  ../util/kudu_export.h
+  ${CMAKE_CURRENT_BINARY_DIR}/../util/kudu_export.h
   ../util/monotime.h
   ../util/slice.h
   ../util/status.h

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/client/client_samples-test.sh
----------------------------------------------------------------------
diff --git a/src/kudu/client/client_samples-test.sh b/src/kudu/client/client_samples-test.sh
index 296bcb2..f1dafef 100755
--- a/src/kudu/client/client_samples-test.sh
+++ b/src/kudu/client/client_samples-test.sh
@@ -41,14 +41,14 @@ cleanup() {
 }
 trap cleanup EXIT
 
-ROOT=$(cd $(dirname "$BASH_SOURCE")/../../..; pwd)
+OUTPUT_DIR=$(cd $(dirname "$BASH_SOURCE"); pwd)
 
 # Install the client library to a temporary directory.
 # Try to detect whether we're building using Ninja or Make.
 LIBRARY_DIR=$(mktemp -d -t kudu-samples-test.XXXXXXXXXXXXX)
 PREFIX_DIR=$LIBRARY_DIR/usr/local
 SAMPLES_DIR=$PREFIX_DIR/share/doc/kuduClient/samples
-pushd $ROOT
+pushd $OUTPUT_DIR/..
 NINJA=$(which ninja 2>/dev/null) || NINJA=""
 if [ -r build.ninja -a -n "$NINJA" ]; then
   DESTDIR=$LIBRARY_DIR ninja install
@@ -77,12 +77,12 @@ export TMPDIR=${TMPDIR:-/tmp}
 export TEST_TMPDIR=${TEST_TMPDIR:-$TMPDIR/kudutest-$UID}
 mkdir -p $TEST_TMPDIR
 BASE_DIR=$(mktemp -d $TEST_TMPDIR/client_samples-test.XXXXXXXX)
-$ROOT/build/latest/kudu-master \
+$OUTPUT_DIR/kudu-master \
   --log_dir=$BASE_DIR \
   --fs_wal_dir=$BASE_DIR/master \
   --fs_data_dirs=$BASE_DIR/master &
 MASTER_PID=$!
-$ROOT/build/latest/kudu-tserver \
+$OUTPUT_DIR/kudu-tserver \
   --log_dir=$BASE_DIR \
   --fs_wal_dir=$BASE_DIR/ts \
   --fs_data_dirs=$BASE_DIR/ts &

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/client/client_symbol-test.sh
----------------------------------------------------------------------
diff --git a/src/kudu/client/client_symbol-test.sh b/src/kudu/client/client_symbol-test.sh
index 4ab86f5..2975967 100755
--- a/src/kudu/client/client_symbol-test.sh
+++ b/src/kudu/client/client_symbol-test.sh
@@ -34,8 +34,7 @@ elif [[ "$OSTYPE" == "darwin"* ]]; then
   DYLIB_SUFFIX="dylib"
 fi
 
-ROOT=$(cd $(dirname "$BASH_SOURCE")/../../..; pwd)
-LIB=$ROOT/build/latest/exported/libkudu_client.$DYLIB_SUFFIX
+LIB=$(dirname "$BASH_SOURCE")/exported/libkudu_client.$DYLIB_SUFFIX
 if [ -r $LIB ]; then
   echo "Found kudu client library: $LIB"
 else

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/codegen/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/codegen/CMakeLists.txt b/src/kudu/codegen/CMakeLists.txt
index 37dc612..a57c04c 100644
--- a/src/kudu/codegen/CMakeLists.txt
+++ b/src/kudu/codegen/CMakeLists.txt
@@ -55,18 +55,20 @@ set(CLANG_EXEC ${THIRDPARTY_PREFIX}/bin/clang++)
 set(IR_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/precompiled.cc)
 set(IR_OUTPUT ${BUILD_OUTPUT_ROOT_DIRECTORY}/precompiled.ll)
 set(IR_OUTPUT_CC ${IR_OUTPUT}.cc)
+
 # Retrieve all includes directories needed for precompilation
-set(IR_INCLUDES
-  -I ${CMAKE_SOURCE_DIR}/src
-  -I ${GLOG_INCLUDE_DIR}
-  -I ${GTEST_INCLUDE_DIR}
-  -I ${Boost_INCLUDE_DIR})
+get_directory_property(IR_INCLUDES
+  DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+  INCLUDE_DIRECTORIES)
+foreach(noprefix ${IR_INCLUDES})
+  set(PREFIXED_IR_INCLUDES ${PREFIXED_IR_INCLUDES} -I${noprefix})
+endforeach()
 
 if (APPLE)
   # OS X keeps the libc++ headers in a non-standard location that the thirdparty
   # Clang does not know about by default.
-  set(IR_INCLUDES
-    ${IR_INCLUDES}
+  set(PREFIXED_IR_INCLUDES
+    ${PREFIXED_IR_INCLUDES}
     -cxx-isystem "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1")
 endif()
 
@@ -77,13 +79,14 @@ get_directory_property(IR_PP_DEFINITIONS
 foreach(noprefix ${IR_PP_DEFINITIONS})
     set(PREFIXED_IR_PP_DEFS ${PREFIXED_IR_PP_DEFS} -D${noprefix})
 endforeach()
+
 # Get flags related to actually compiling the source
 set(IR_FLAGS
   -S -emit-llvm
   -DIR_BUILD
   ${CMAKE_CXX_FLAGS}
   ${PREFIXED_IR_PP_DEFS}
-  ${IR_INCLUDES})
+  ${PREFIXED_IR_INCLUDES})
 separate_arguments(IR_FLAGS)
 
 # Avoid enabling ASAN in the precompiled IR.

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/scripts/benchmarks.sh
----------------------------------------------------------------------
diff --git a/src/kudu/scripts/benchmarks.sh b/src/kudu/scripts/benchmarks.sh
index b580160..bd722f8 100755
--- a/src/kudu/scripts/benchmarks.sh
+++ b/src/kudu/scripts/benchmarks.sh
@@ -174,23 +174,30 @@ build_kudu() {
   export PPROF_PATH=$THIRDPARTY_BIN/pprof
 
   # Build Kudu
-  rm -rf CMakeCache.txt CMakeFiles
+  rm -rf build
+  mkdir -p build
+  pushd build
 
   BUILD_TYPE=release
   # Workaround for gperftools issue #497
   export LD_BIND_NOW=1
 
-  $BASE_DIR/build-support/enable_devtoolset.sh $THIRDPARTY_BIN/cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
-  make clean
+  $BASE_DIR/build-support/enable_devtoolset.sh $THIRDPARTY_BIN/cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ..
+
   # clean up before we run
   rm -Rf /tmp/kudutpch1-$UID
   mkdir -p /tmp/kudutpch1-$UID
 
   NUM_PROCS=$(cat /proc/cpuinfo | grep processor | wc -l)
   make -j${NUM_PROCS} 2>&1 | tee build.log
+  popd
+
 }
 
 run_benchmarks() {
+  # Create output directories if needed.
+  mkdir -p "$LOGDIR"
+  mkdir -p "$OUTDIR"
 
   # run all of the variations of mt-tablet-test
   ./build/latest/mt-tablet-test \
@@ -617,17 +624,6 @@ restore_governor() {
 }
 trap restore_governor EXIT
 
-# Create output directories if needed.
-[ -d "$LOGDIR" ] || mkdir -p "$LOGDIR"
-[ -d "$OUTDIR" ] || mkdir -p "$OUTDIR"
-
-# Clean up files from previous runs.
-rm -f $LOGDIR/*.log
-rm -f $LOGDIR/*.txt
-rm -f $OUTDIR/*.tsv
-rm -f $OUTDIR/*.png
-rm -f $OUTDIR/*.html
-
 # Kick off the benchmark script.
 run $*
 

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/scripts/tpch.sh
----------------------------------------------------------------------
diff --git a/src/kudu/scripts/tpch.sh b/src/kudu/scripts/tpch.sh
index 09dec47..eee47de 100755
--- a/src/kudu/scripts/tpch.sh
+++ b/src/kudu/scripts/tpch.sh
@@ -96,17 +96,19 @@ THIRDPARTY_BIN=$(pwd)/thirdparty/installed/bin
 export PPROF_PATH=$THIRDPARTY_BIN/pprof
 
 # Build Kudu
-rm -rf CMakeCache.txt CMakeFiles
+rm -rf build
+mkdir -p build
+pushd build
 
 BUILD_TYPE=release
 # Workaround for gperftools issue #497
 export LD_BIND_NOW=1
 
-$ROOT/build-support/enable_devtoolset.sh $THIRDPARTY_BIN/cmake . -DCMAKE_BUILD_TYPE=${BUILD_TYPE}
-make clean
+$ROOT/build-support/enable_devtoolset.sh $THIRDPARTY_BIN/cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} ..
 
 NUM_PROCS=$(cat /proc/cpuinfo | grep processor | wc -l)
 make -j${NUM_PROCS} tpch1 2>&1 | tee build.log
+popd
 
 # Warming up the OS buffer.
 cat $LINEITEM_TBL_PATH > /dev/null
@@ -115,11 +117,11 @@ cat $LINEITEM_TBL_PATH > /dev/null
 rm -Rf $KUDU_DATA_DIR   # Clean up data dir.
 mkdir -p $OUTDIR        # Create log file output dir.
 
-./build/release/tpch1 -logtostderr=1 \
-                      -tpch_path_to_data=$LINEITEM_TBL_PATH \
-                      -mini_cluster_base_dir=$KUDU_DATA_DIR \
-                      -tpch_num_query_iterations=$TPCH_NUM_QUERY_ITERS \
-                      >$OUTDIR/benchmark.log 2>&1
+./build/latest/tpch1 -logtostderr=1 \
+                     -tpch_path_to_data=$LINEITEM_TBL_PATH \
+                     -mini_cluster_base_dir=$KUDU_DATA_DIR \
+                     -tpch_num_query_iterations=$TPCH_NUM_QUERY_ITERS \
+                     >$OUTDIR/benchmark.log 2>&1
 
 cat $OUTDIR/benchmark.log
 INSERT_TIME=$(grep "Time spent loading" $OUTDIR/benchmark.log | \

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/twitter-demo/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/twitter-demo/CMakeLists.txt b/src/kudu/twitter-demo/CMakeLists.txt
index c7e8e21..e6b4471 100644
--- a/src/kudu/twitter-demo/CMakeLists.txt
+++ b/src/kudu/twitter-demo/CMakeLists.txt
@@ -53,6 +53,10 @@ else()
       twitter_demo)
     target_link_libraries(parser-test
       twitter_demo)
+    execute_process(COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/example-tweets.txt
+      ${EXECUTABLE_OUTPUT_PATH})
+    execute_process(COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/example-deletes.txt
+      ${EXECUTABLE_OUTPUT_PATH})
   endif()
 
 endif() # library checks

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/twitter-demo/parser-test.cc
----------------------------------------------------------------------
diff --git a/src/kudu/twitter-demo/parser-test.cc b/src/kudu/twitter-demo/parser-test.cc
index 1085450..2870864 100644
--- a/src/kudu/twitter-demo/parser-test.cc
+++ b/src/kudu/twitter-demo/parser-test.cc
@@ -37,9 +37,7 @@ static string GetExecutableDir() {
 }
 
 static Status LoadFile(const string& name, vector<string>* lines) {
-  // The test runs from build/debug|release/, so go up two directories
-  // to get back to the source dir.
-  string path = GetExecutableDir() + "/" + "../../src/kudu/twitter-demo/" + name;
+  string path = JoinPathSegments(GetExecutableDir(), name);
   faststring data;
   RETURN_NOT_OK(ReadFileToString(Env::Default(), path, &data));
 

http://git-wip-us.apache.org/repos/asf/incubator-kudu/blob/3e8d29f4/src/kudu/util/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/kudu/util/CMakeLists.txt b/src/kudu/util/CMakeLists.txt
index a01c8e5..523e57e 100644
--- a/src/kudu/util/CMakeLists.txt
+++ b/src/kudu/util/CMakeLists.txt
@@ -61,7 +61,7 @@ ADD_EXPORTABLE_LIBRARY(version_info_proto
 # Version stamp
 ############################################################
 include_directories(${BUILD_OUTPUT_ROOT_DIRECTORY})
-set(VERSION_STAMP_FILE ${BUILD_OUTPUT_ROOT_DIRECTORY}kudu/generated/version_defines.h)
+set(VERSION_STAMP_FILE ${BUILD_OUTPUT_ROOT_DIRECTORY}/kudu/generated/version_defines.h)
 list(APPEND GEN_VERSION_INFO_COMMAND "${BUILD_SUPPORT_DIR}/gen_version_info.py")
 list(APPEND GEN_VERSION_INFO_COMMAND "--version=${KUDU_VERSION_NUMBER}")
 list(APPEND GEN_VERSION_INFO_COMMAND "--build-type=${CMAKE_BUILD_TYPE}")