Skip to content

Commit

Permalink
Merge pull request #108 from PRUNERS/issue106-fix-incremental-runbuild
Browse files Browse the repository at this point in the history
Issue106 fix incremental runbuild
  • Loading branch information
mikebentley15 authored Jan 9, 2018
2 parents 22f4e4f + 7517d31 commit 622853b
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 7 deletions.
22 changes: 15 additions & 7 deletions data/Makefile.in
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,10 @@ DEV_CUOBJ += $(addprefix $(OBJ_DIR)/,$(notdir $(CUSOURCE:%.cpp=%_cu_dev.o)
VPATH += $(dir $(CUSOURCE))

NVCC_BIN := nvcc
NVCC := $(shell which $(NVCC_BIN))
CUDA_DIR := $(dir $(NVCC))/..

HAS_CUDA := $(shell command -v $(NVCC_BIN) 2> /dev/null)
ifdef HAS_CUDA
NVCC := $(shell which $(NVCC_BIN) 2>/dev/null)
CUDA_DIR := $(dir $(NVCC))/..
NVCC_CFLAGS += --std=c++11
NVCC_CFLAGS += -ccbin=g++
NVCC_CFLAGS += $(DEVCAP)
Expand Down Expand Up @@ -134,7 +133,8 @@ INTEL := icpc
GCC := g++

ifndef CUDA_ONLY
COMPILERS := $(foreach c, GCC INTEL CLANG, $(if $(shell which $($(c))), $c,))
COMPILERS := $(foreach c, GCC INTEL CLANG, \
$(if $(shell which $($(c)) 2>/dev/null), $c,))
endif

ifdef CLANG_ONLY
Expand All @@ -147,7 +147,7 @@ RESULTS_DIR := results

# on systems with non-standard gcc installations (such as module), clang may
# be unable to determine the correct gcc toolchain
GCC_TOOLCHAIN := $(dir $(shell which $(GCC)))/..
GCC_TOOLCHAIN := $(dir $(shell which $(GCC) 2>/dev/null))/..
CLANG_REQUIRED := --gcc-toolchain=$(GCC_TOOLCHAIN)

# Compiler setting targets
Expand Down Expand Up @@ -363,7 +363,7 @@ $(OBJ_DIR)/%_$(R_ID).o: %.cpp Makefile custom.mk | $(OBJ_DIR)
-DFLIT_FILENAME='"$(R_ID)"'

# Otherwise, we're not in a recursion.
else
else # ifndef R_IS_RECURSED

$(OBJ_DIR):
mkdir -p $(OBJ_DIR)
Expand All @@ -387,7 +387,11 @@ TARGETS += $$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip
# TODO: use the variable $$(MAKECMDGOALS) to get the original make target
# or see if it is even necessary

$$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2): | $$(OBJ_DIR) $$(RESULTS_DIR)
# Make the recursive target depend on $$(GT_TARGET), not because it actually
# depends on that target, but we know that when $$(GT_TARGET) needs to be
# rebuilt, so does each recursive target.

$$(RESULTS_DIR)/$(strip $1)_$$(HOSTNAME)_$(strip $3)_$(strip $2): $$(GT_TARGET) | $$(OBJ_DIR) $$(RESULTS_DIR)
-$$(MAKE) rec \
R_IS_RECURSED=True \
R_CUR_COMPILER=$(strip $1) \
Expand Down Expand Up @@ -484,6 +488,10 @@ $(TARGETS): $(FLIT_LIB_DIR)/libflit.so
$(CUTARGETS): $(FLIT_LIB_DIR)/libflit.so
endif # ifeq ($(UNAME_S),Darwin): meaning, we are on a mac

# include the build dependencies for gt and dev

-include $(GT_DEPS)
-include $(DEV_DEPS)

#
# Now for the compilation rules:
Expand Down
2 changes: 2 additions & 0 deletions tests/flit_makefile/tst_empty_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
Let's actually now compile and run the empty test under different circumstances
TODO: this takes too long to run. Can we do something faster?
>>> import subprocess as subp
>>> with th.tempdir() as temp_dir:
... th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS
Expand Down
107 changes: 107 additions & 0 deletions tests/flit_makefile/tst_incremental_build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
'''
Tests FLiT's generated Makefile and its ability to correctly do incremental
builds.
The tests are below using doctest
>>> import glob
>>> import os
>>> import subprocess as subp
>>> import re
>>> import time
Test that the dev target will be rebuilt if one of the files is updated.
We use 'make --touch' to simply touch files it would create and then we will
test that the correct files are updated.
>>> def compile_target(directory, target):
... 'Compiles the dev target using "make --touch" and returns the output'
... output = subp.check_output(['make', '-C', directory, '--touch', target])
... return output.decode('utf-8').strip()
>>> compile_dev = lambda x: compile_target(x, 'dev')
>>> with th.tempdir() as temp_dir:
... th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS
... # fake the built elements -- don't actually build for time's sake
... os.mkdir(os.path.join(temp_dir, 'obj'))
... before_build = compile_dev(temp_dir)
... # this next build should say nothing to do
... after_build = compile_dev(temp_dir)
... # update one file and recompile
... with open(os.path.join(temp_dir, 'main.cpp'), 'a') as mainfile:
... mainfile.write('#include "new_header.h"\\n')
... with open(os.path.join(temp_dir, 'obj', 'main_dev.d'), 'w') as maindep:
... maindep.write('obj/main_dev.o: main.cpp new_header.h\\n')
... th.touch(os.path.join(temp_dir, 'new_header.h'))
... after_modify = compile_dev(temp_dir)
... # touch the header file and make sure it recompiles again
... time.sleep(0.001) # give some time before touching again
... th.touch(os.path.join(temp_dir, 'new_header.h'))
... after_touch = compile_dev(temp_dir)
Creating ...
>>> def touched_files(outstring):
... 'Returns list of touched files in sorted order'
... return sorted([x[6:] for x in outstring.splitlines()
... if x.startswith('touch ')])
Make sure all of the correct files were created with our build commands
>>> touched_files(before_build)
['devrun', 'obj/Empty_dev.o', 'obj/main_dev.o']
>>> touched_files(after_build)
[]
>>> touched_files(after_modify)
['devrun', 'obj/main_dev.o']
>>> touched_files(after_touch)
['devrun', 'obj/main_dev.o']
Now, let's test the same thing with the "gt" target
>>> compile_gt = lambda x: compile_target(x, 'gt')
>>> with th.tempdir() as temp_dir:
... th.flit.main(['init', '-C', temp_dir]) # doctest:+ELLIPSIS
... # fake the built elements -- don't actually build for time's sake
... os.mkdir(os.path.join(temp_dir, 'obj'))
... before_build = compile_gt(temp_dir)
... # this next build should say nothing to do
... after_build = compile_gt(temp_dir)
... # update one file and recompile
... with open(os.path.join(temp_dir, 'main.cpp'), 'a') as mainfile:
... mainfile.write('#include "new_header.h"\\n')
... with open(os.path.join(temp_dir, 'obj', 'main_gt.d'), 'w') as maindep:
... maindep.write('obj/main_gt.o: main.cpp new_header.h\\n')
... th.touch(os.path.join(temp_dir, 'new_header.h'))
... after_modify = compile_gt(temp_dir)
... # touch the header file and make sure it recompiles again
... time.sleep(0.001) # give some time before touching again
... th.touch(os.path.join(temp_dir, 'new_header.h'))
... after_touch = compile_gt(temp_dir)
Creating ...
Make sure all of the correct files were created with our build commands
>>> touched_files(before_build)
['gtrun', 'obj/Empty_gt.o', 'obj/main_gt.o']
>>> touched_files(after_build)
[]
>>> touched_files(after_modify)
['gtrun', 'obj/main_gt.o']
>>> touched_files(after_touch)
['gtrun', 'obj/main_gt.o']
'''

# Test setup before the docstring is run.
import sys
before_path = sys.path[:]
sys.path.append('..')
import test_harness as th
sys.path = before_path

if __name__ == '__main__':
import doctest
doctest.testmod()
8 changes: 8 additions & 0 deletions tests/test_harness.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,14 @@ def tempdir(*args, **kwargs):
yield new_dir
shutil.rmtree(new_dir)

def touch(filename):
'''
Create an emtpy file if it does not exist, otherwise updates the
modification time.
'''
from pathlib import Path
Path(filename).touch()

flit = _path_import(_script_dir, 'flit')
config = _path_import(_script_dir, 'flitconfig')

Expand Down

0 comments on commit 622853b

Please sign in to comment.