diff --git a/hpvm/cmake/BuildNVDLA.cmake b/hpvm/cmake/BuildNVDLA.cmake
new file mode 100644
index 0000000000000000000000000000000000000000..12f8237b679c6fe14cc6e9430865e16e33a14304
--- /dev/null
+++ b/hpvm/cmake/BuildNVDLA.cmake
@@ -0,0 +1,60 @@
+get_filename_component(NVDLA_DIR ${NVDLA_DIR} ABSOLUTE)
+set(NVDLA_UMD_DIR ${NVDLA_DIR}/umd)
+set(NVDLA_LIB_DIR ${NVDLA_DIR}/lib)
+make_directory(${NVDLA_LIB_DIR})
+
+# Build Protobuf
+set(PROTOBUF_DIR ${NVDLA_UMD_DIR}/external/protobuf-2.6)
+set(COMPILER_APPS_DIR ${NVDLA_UMD_DIR}/apps/compiler)
+set(COMPILER_CORE_DIR ${NVDLA_UMD_DIR}/core/src/compiler)
+add_custom_command(
+  OUTPUT
+    ${COMPILER_CORE_DIR}/libprotobuf.a ${COMPILER_APPS_DIR}/libprotobuf.a
+    ${NVDLA_LIB_DIR}/libprotobuf.so  # Final product 1
+  WORKING_DIRECTORY ${PROTOBUF_DIR}
+  COMMAND ./autogen.sh && ./configure && make
+  COMMAND cp ./src/.libs/libprotobuf.a ${COMPILER_CORE_DIR}
+  COMMAND cp ./src/.libs/libprotobuf.a ${COMPILER_APPS_DIR}
+  # Some versions of OS may need all of these:
+  COMMAND mkdir -p ${NVDLA_LIB_DIR}
+  COMMAND cp ./src/.libs/libprotobuf.so ${NVDLA_LIB_DIR}/libprotobuf.so.9.0.1
+  COMMAND ln -s ${NVDLA_LIB_DIR}/libprotobuf.so.9.0.1 ${NVDLA_LIB_DIR}/libprotobuf.so.9
+  COMMAND ln -s ${NVDLA_LIB_DIR}/libprotobuf.so.9 ${NVDLA_LIB_DIR}/libprotobuf.so
+)
+
+# Build NVDLA library
+add_custom_command(
+  OUTPUT ${COMPILER_APPS_DIR}/libnvdla_compiler.so  # Final product 2
+  WORKING_DIRECTORY ${NVDLA_UMD_DIR}
+  COMMAND make TOP=${NVDLA_UMD_DIR}
+  COMMAND cp ${NVDLA_UMD_DIR}/out/core/src/compiler/libnvdla_compiler/libnvdla_compiler.so ${COMPILER_APPS_DIR}
+)
+
+# What's funny is Make and Ninja don't see these .so files without a custom target
+# even though the user of these files is right there (NVDLA)
+# So we add these custom target rules here.
+add_custom_target(nvdla-protobuf DEPENDS ${NVDLA_LIB_DIR}/libprotobuf.so)
+add_custom_target(nvdla-compiler DEPENDS ${COMPILER_APPS_DIR}/libnvdla_compiler.so)
+
+add_library(NVDLA INTERFACE)
+target_include_directories(
+  NVDLA INTERFACE
+  $<BUILD_INTERFACE:${NVDLA_DIR}/umd/external/include>
+  $<BUILD_INTERFACE:${NVDLA_DIR}/umd/core/include>
+  $<BUILD_INTERFACE:${NVDLA_DIR}/umd/core/src/common/include>
+  $<BUILD_INTERFACE:${NVDLA_DIR}/umd/core/src/compiler/include>
+  $<INSTALL_INTERFACE:include/umd>
+)
+target_link_libraries(
+  NVDLA INTERFACE
+  ${COMPILER_APPS_DIR}/libnvdla_compiler.so
+  ${NVDLA_LIB_DIR}/libprotobuf.so
+)
+add_dependencies(NVDLA nvdla-protobuf nvdla-compiler)
+
+# LLVM wants to every lib/ module to be installable,
+# so as a dependency of a lib/ module, NVDLA must also be installable.
+# N.B.: what we write here will not necessarily work for users who install HPVM
+# (we haven't figured that out yet); this is just to make CMake happy.
+install(TARGETS NVDLA EXPORT LLVMExports)
+set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS_BUILDTREE_ONLY NVDLA)
diff --git a/hpvm/lib/Transforms/HPVM2NVDLA/CMakeLists.txt b/hpvm/lib/Transforms/HPVM2NVDLA/CMakeLists.txt
index 2e82ec555ab9d089e8b0cc58402a1692cee45beb..8187f3f86b9ba36379f25146b8dcb2f637db711e 100644
--- a/hpvm/lib/Transforms/HPVM2NVDLA/CMakeLists.txt
+++ b/hpvm/lib/Transforms/HPVM2NVDLA/CMakeLists.txt
@@ -4,31 +4,12 @@ endif()
 
 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DLLVM_BUILD_DIR=${CMAKE_BINARY_DIR}")
 
-add_definitions(-DNVDLA_UTILS_ERROR_TAG="DLA")
-
-include_directories(../../../sw/umd/external/include)
-include_directories(../../../sw/umd/core/include)
-include_directories(../../../sw/umd/core/src/common/include)
-include_directories(../../../sw/umd/core/src/compiler/include)
-
-add_llvm_library( LLVMHPVM2NVDLAPass
-  MODULE
-  HPVM2NVDLAPass.cpp
-
-  DEPENDS
-  intrinsics_gen
-  PLUGIN_TOOL
-  opt
-  )
-
-find_library(NVDLA_COMPILER
-    NAMES nvdla_compiler
-    HINTS ../../../sw/lib
+add_llvm_library(
+  LLVMHPVM2NVDLAPass
+  MODULE HPVM2NVDLAPass.cpp
+  DEPENDS intrinsics_gen
+  PLUGIN_TOOL opt
 )
-
-find_library(PROTOBUF
-    NAMES protobuf
-    HINTS ../../../sw/lib
-)
-
-target_link_libraries(LLVMHPVM2NVDLAPass ${NVDLA_COMPILER} ${PROTOBUF})
+target_compile_definitions(LLVMHPVM2NVDLAPass PRIVATE -DNVDLA_UTILS_ERROR_TAG="DLA")
+# Links against NVDLA
+target_link_libraries(LLVMHPVM2NVDLAPass NVDLA)
diff --git a/hpvm/projects/CMakeLists.txt b/hpvm/projects/CMakeLists.txt
index 4eaf1094e47b9fe7fd4a397a07923bde7e3beca3..68133ae848355638723839ce9834828bde4c81bb 100644
--- a/hpvm/projects/CMakeLists.txt
+++ b/hpvm/projects/CMakeLists.txt
@@ -13,3 +13,10 @@ endforeach(entry)
 if(HPVM_USE_CUDA)
   add_llvm_external_project(hpvm-tensor-rt)
 endif()
+
+# Build NVDLA if ./sw exists
+set(NVDLA_DIR ${CMAKE_CURRENT_SOURCE_DIR}/sw)
+if(IS_DIRECTORY ${NVDLA_DIR})
+  # This uses the variable ${NVDLA_DIR} creates an Interface library NVDLA
+  include(../cmake/BuildNVDLA.cmake)
+endif()
diff --git a/hpvm/scripts/hpvm_installer.py b/hpvm/scripts/hpvm_installer.py
index d6e6ea76fb288d93ae57dd8e4a802bbe1c60b617..c480f485d5a6cea9dc33303a5821e5a3f2b8ec7d 100755
--- a/hpvm/scripts/hpvm_installer.py
+++ b/hpvm/scripts/hpvm_installer.py
@@ -19,17 +19,7 @@ MODEL_PARAMS_DIR = ROOT_DIR / "test/dnn_benchmarks/model_params"
 MODEL_PARAMS_LINK = "https://databank.illinois.edu/datafiles/o3izd/download"
 
 NVDLA_URL = "https://github.com/nvdla/sw.git"
-NVDLA_DIR = ROOT_DIR / "sw"
-NVDLA_UMD_DIR = NVDLA_DIR / "umd"
-PROTOBUF_DIR = NVDLA_UMD_DIR / "external/protobuf-2.6"
-PROTOBUF_STATIC_LIB = PROTOBUF_DIR / "src/.libs/libprotobuf.a"
-COMPILER_APPS_DIR = NVDLA_UMD_DIR / "apps/compiler"
-COMPILER_CORE_DIR = NVDLA_UMD_DIR / "core/src/compiler"
-NVDLA_LIB = NVDLA_UMD_DIR / "out/core/src/compiler/libnvdla_compiler/libnvdla_compiler.so"
-PROTOBUF_LIB = PROTOBUF_DIR / "src/.libs/libprotobuf.so"
-PROTOBUF_LIB_V1 = "libprotobuf.so.9"   # Some versions of OS may need this
-PROTOBUF_LIB_V2 = "libprotobuf.so.9.0.1"  # Some versions of OS may need this
-NVDLA_LIB_DIR = NVDLA_DIR / "lib"
+NVDLA_DIR = ROOT_DIR / "projects/sw"
 
 LINKS = [
     "CMakeLists.txt",
@@ -170,11 +160,13 @@ Example: "DCMAKE_BUILD_TYPE=Release DCMAKE_INSTALL_PREFIX=install".
 Arguments: """
     )
     args.cmake_args = input()
-    if args.cmake_args.strip() != "":    
-      args.cmake_args = [f"-{arg}" for arg in args.cmake_args.split(" ")]
+    if args.cmake_args.strip() != "":
+        args.cmake_args = [f"-{arg}" for arg in args.cmake_args.split(" ")]
 
     args.no_pypkg = not input_with_check(
-        "Install HPVM Python Packages (recommended)? [y/n]: ", parse_yn, "Please enter y or n"
+        "Install HPVM Python Packages (recommended)? [y/n]: ",
+        parse_yn,
+        "Please enter y or n",
     )
     args.no_params = not input_with_check(
         "Download DNN weights (recommended)? [y/n]: ", parse_yn, "Please enter y or n"
@@ -200,7 +192,7 @@ def print_args(args):
 
 def check_python_version():
     from sys import version_info, version, executable
-    
+
     lowest, highest = PYTHON_REQ
     if not (lowest <= version_info < highest):
         lowest_str = ".".join([str(n) for n in lowest])
@@ -275,13 +267,14 @@ def check_download_model_params():
     if MODEL_PARAMS_TAR.is_file():
         MODEL_PARAMS_TAR.unlink()
 
+
 def check_download_nvdla_sw():
     if NVDLA_DIR.is_dir():
         print("Found NVDLA compiler, not downloading it again.")
         return
-    print(f"Downloading the NVDLA compiler...")
+    print(f"Downloading the NVDLA compiler into {NVDLA_DIR}...")
     print(f"=============================")
-    check_call(["git", "clone", NVDLA_URL])
+    check_call(["git", "clone", NVDLA_URL, NVDLA_DIR])
 
 
 def link_and_patch():
@@ -303,26 +296,6 @@ def link_and_patch():
     chdir(cwd)
 
 
-def build_nvdla_compiler():
-    print("Building NVDLA compiler...")
-    chdir(PROTOBUF_DIR)
-    check_call(["./autogen.sh"])
-    check_call(["./configure"])
-    check_call(["make"])
-    check_call(["cp", PROTOBUF_STATIC_LIB, COMPILER_CORE_DIR])
-    check_call(["cp", PROTOBUF_STATIC_LIB, COMPILER_APPS_DIR])
-    chdir(NVDLA_UMD_DIR)
-    check_call(["make", "TOP="  + str(NVDLA_UMD_DIR)])
-
-    # Copy over the NVDLA and Protobuf libraries to 
-    # a single directory
-    #check_call(["mkdir", NVDLA_LIB_DIR])
-    makedirs(NVDLA_LIB_DIR, exist_ok=True)
-    check_call(["cp", NVDLA_LIB, NVDLA_LIB_DIR])
-    check_call(["cp", PROTOBUF_LIB, NVDLA_LIB_DIR])
-    check_call(["cp", PROTOBUF_LIB, str(NVDLA_LIB_DIR) + "/" + PROTOBUF_LIB_V1])
-    check_call(["cp", PROTOBUF_LIB, str(NVDLA_LIB_DIR) + "/" + PROTOBUF_LIB_V2])
-
 def build(
     build_dir: Path,
     nthreads: int,
@@ -336,7 +309,6 @@ def build(
 
     cwd = Path.cwd()
     chdir(build_dir)
-    build_nvdla_compiler()
     cmake_args = [
         "cmake",
         str(ROOT_DIR / "llvm"),