gollvm: add cmake controls for go compiler dependence

In typical use cases, we want to cmake to force a rebuild of all
objects built from Go source if the compiler binary changes For
compiler developers, however, this dependence can be a hassle-- when
iterating on compiler changes, it is annoying to have each tiny change
force a library rebuild.

To help with this, create a new (unsafe) DISABLE_LIBGO_GOC_DEP cmake
control variable that can be enabled by compiler developers to break
the dependence on the compiler for all llvm-goc compiled objects. If
DISABLE_LIBGO_GOC_DEP, objects depend on a token file that gets
created once the first copy of the compiler is built (the token file
is not updated when the compiler is rebuilt).

Change-Id: I5267c3106abd79db822e0ab2b1ac1387833969a5
Reviewed-on: https://go-review.googlesource.com/112355
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ded072f..f468ed6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,6 +12,8 @@
 
 list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
 
+include(CmakeUtils)
+
 # So that we can issue "make -jN" cmds in externalproject_add
 processorcount(PROCESSOR_COUNT)
 
@@ -65,6 +67,20 @@
   LOG_INSTALL 1
   )
 
+# In most use cases, we want to force a rebuild of all objects built
+# from Go source if the compiler changes.
+set(gocdep llvm-goc llvm-goc-token)
+
+# For compiler developers, however, the dependence this can be a
+# hassle-- when hacking on the compiler, it is annoying to have each
+# tiny change force a library rebuild, so the DISABLE_LIBGO_GOC_DEP can
+# be set as an (unsafe) escape hatch to break the dependence from golibs
+# to compiler. In this case we still need to insure that the compiler
+# exists, but we don't care whether it is up to date or not.
+if (DISABLE_LIBGO_GOC_DEP)
+  set(gocdep llvm-goc-token)
+endif()
+
 # Root of gollvm source code.
 set(GOLLVM_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
 
diff --git a/cmake/AutoGenGo.cmake b/cmake/AutoGenGo.cmake
index 0f9fde7..ab5d51f 100644
--- a/cmake/AutoGenGo.cmake
+++ b/cmake/AutoGenGo.cmake
@@ -1,31 +1,4 @@
 
-# Helper function to copy file X to file Y if X and Y are different.
-#
-# Unnamed parameters:
-#
-#   * src file path
-#   * target file path
-#
-# Named parameters:
-#
-# COMMENT  comment string to use other than the default
-function(copy_if_different inpath outpath)
-  CMAKE_PARSE_ARGUMENTS(ARG "" "COMMENT" "" ${ARGN})
-  get_filename_component(infile "${inpath}" NAME)
-  get_filename_component(outfile "${outpath}" NAME)
-  set(comment "Updating ${outfile} from ${infile}")
-  if(NOT ARG_COMMENT)
-    set(comment "${ARG_COMMENT}")
-  endif()
-  add_custom_command(
-    OUTPUT "${outpath}"
-    COMMAND  ${CMAKE_COMMAND} -E copy_if_different
-       ${inpath} ${outpath}
-    DEPENDS ${inpath}
-    COMMENT "${comment}"
-    VERBATIM)
-endfunction()
-
 #----------------------------------------------------------------------
 # Emit 'version.go'. This file contains a series of Go constants that
 # capture the target configuration (arch, OS, etc), emitted directly
diff --git a/cmake/CmakeUtils.cmake b/cmake/CmakeUtils.cmake
new file mode 100644
index 0000000..f1459e7
--- /dev/null
+++ b/cmake/CmakeUtils.cmake
@@ -0,0 +1,28 @@
+
+# Helper function to copy file X to file Y if X and Y are different.
+#
+# Unnamed parameters:
+#
+#   * src file path
+#   * target file path
+#
+# Named parameters:
+#
+# COMMENT  comment string to use other than the default
+function(copy_if_different inpath outpath)
+  CMAKE_PARSE_ARGUMENTS(ARG "" "COMMENT" "" ${ARGN})
+  get_filename_component(infile "${inpath}" NAME)
+  get_filename_component(outfile "${outpath}" NAME)
+  set(comment "Updating ${outfile} from ${infile}")
+  if(NOT ARG_COMMENT)
+    set(comment "${ARG_COMMENT}")
+  endif()
+  add_custom_command(
+    OUTPUT "${outpath}"
+    COMMAND  ${CMAKE_COMMAND} -E copy_if_different
+       ${inpath} ${outpath}
+    DEPENDS ${inpath}
+    COMMENT "${comment}"
+    VERBATIM)
+endfunction()
+
diff --git a/cmake/GoPackage.cmake b/cmake/GoPackage.cmake
index 4164a21..c22a419 100644
--- a/cmake/GoPackage.cmake
+++ b/cmake/GoPackage.cmake
@@ -60,7 +60,7 @@
     OUTPUT ${package_ofile}
     COMMAND ${CMAKE_COMMAND} -E make_directory "./${pdir}"
     COMMAND "${gocompiler}" "-c" "-o" ${package_ofile} "-fgo-pkgpath=${pkgpath}" ${ARG_GOCFLAGS} -I . ${ARG_GOSRC}
-    DEPENDS ${ARG_GOSRC} ${godeps}
+    DEPENDS ${ARG_GOSRC} ${godeps} ${gocdep}
     COMMENT "Building Go package '${pkgpath}' (non-PIC)"
     VERBATIM)
   list(APPEND pkg_outputs "${package_ofile}")
@@ -71,7 +71,7 @@
       OUTPUT "${package_picofile}"
       COMMAND ${CMAKE_COMMAND} -E make_directory "./${pdir}/.pic"
       COMMAND "${gocompiler}" "-c" "-o" ${package_picofile} -fPIC "-fgo-pkgpath=${pkgpath}" ${ARG_GOCFLAGS} -I . ${ARG_GOSRC}
-      DEPENDS ${ARG_GOSRC} ${godeps}
+      DEPENDS ${ARG_GOSRC} ${godeps} ${gocdep}
       COMMENT "Building Go package '${pkgpath}' (PIC)"
       VERBATIM)
     list(APPEND pkg_outputs "${package_picofile}")
diff --git a/driver-main/CMakeLists.txt b/driver-main/CMakeLists.txt
index 66b4ea1..9ac9449 100644
--- a/driver-main/CMakeLists.txt
+++ b/driver-main/CMakeLists.txt
@@ -41,3 +41,22 @@
   PRIVATE
   "-L${EXTLIBDIR}" "-lmpc" "-lmpfr" "-lgmp"
   )
+
+# Create a "compiler built" file each time llvm-goc is built.
+set(llvm_goc_build ${CMAKE_CURRENT_BINARY_DIR}/llvm-goc.built)
+add_custom_command(
+  OUTPUT ${llvm_goc_build}
+  COMMAND  ${CMAKE_COMMAND} -E touch ${llvm_goc_build}
+  DEPENDS llvm-goc
+  COMMENT "Create 'build-performed' file for llvm-goc"
+  VERBATIM)
+
+# Copy the build file to the token file if different. The intent here
+# is that the token file gets created in the process of building
+# llvm-goc, but does NOT get updated each time llvm-goc is rebuilt.
+set(llvm_goc_token ${CMAKE_CURRENT_BINARY_DIR}/llvm-goc.token)
+copy_if_different(${llvm_goc_build} ${llvm_goc_token})
+
+# Token target.
+add_custom_target(llvm-goc-token ALL DEPENDS ${llvm_goc_token})
+