From 13a15ee4545da955bdfc4a040c3b8e485621e398 Mon Sep 17 00:00:00 2001
From: Daniel Stonier <d.stonier@gmail.com>
Date: Thu, 26 Jun 2014 10:54:45 +0900
Subject: [PATCH] solved some hideous cmake dependency sequencing issues.

---
 cmake/genjava-extras.cmake.em                 |  64 +++++++++++++-----
 src/genjava/genjava_main.py                   |   7 +-
 src/genjava/genjava_main.pyc                  | Bin 1300 -> 1631 bytes
 src/genjava/gradle_project.py                 |  21 +++++-
 .../templates/genjava_project/build.gradle.in |  25 ++++++-
 5 files changed, 93 insertions(+), 24 deletions(-)

diff --git a/cmake/genjava-extras.cmake.em b/cmake/genjava-extras.cmake.em
index f08631d..dd6ed36 100644
--- a/cmake/genjava-extras.cmake.em
+++ b/cmake/genjava-extras.cmake.em
@@ -40,51 +40,72 @@ endmacro()
 # To facilitate this, the ARG_GENERATED_FILES is actually just the underlying ARG_MSG and ARG_SRV
 # files which we feed the commands as DEPENDS to trigger their execution.
 macro(_generate_module_java ARG_PKG ARG_GEN_OUTPUT_DIR ARG_GENERATED_FILES)
-
     ################################
     # Gradle Subproject
     ################################
     set(GRADLE_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/java")
     set(GRADLE_BUILD_FILE "${GRADLE_BUILD_DIR}/${ARG_PKG}/build.gradle")
     list(APPEND ALL_GEN_OUTPUT_FILES_java ${GRADLE_BUILD_FILE})
-
+    # a marker for the compiling script later to discover
+    # this command will only get run when an underlying dependency changes, whereas the compiling
+    # add_custom_target always runs (this was so we can ensure compile time dependencies are ok).
+    # So we leave this dropping to inform it when gradle needs to run so that we can skip by
+    # without the huge latency whenever we don't.
+    set(DROPPINGS_FILE "${GRADLE_BUILD_DIR}/${ARG_PKG}/droppings")
     add_custom_command(OUTPUT ${GRADLE_BUILD_FILE}
-        DEPENDS ${GENJAVA_BIN}
+        DEPENDS ${GENJAVA_BIN} ${ARG_GENERATED_FILES}
         COMMAND ${CATKIN_ENV} ${PYTHON_EXECUTABLE} ${GENJAVA_BIN}
             -o ${GRADLE_BUILD_DIR}
             -p ${ARG_PKG}
+        COMMAND touch ${DROPPINGS_FILE}
         COMMENT "Generating Java gradle project from ${ARG_PKG}"
     )
 
     ################################
     # Compile Gradle Subproject
     ################################
+    # Push the compile back to the last thing that gets done before the generate messages
+    # is done for this package (see the PRE_LINK coupled with the TARGET option below). This
+    # is different to genpy, gencpp since it's a compile step. If you don't force it to be
+    # the last thing, then it may be trying to compile while dependencies are still getting
+    # themselves ready for ${ARG_PKG}_generate_messages in parallel.
+    # (i.e. beware of sequencing add_custom_command, it usually has to compete)
     set(ROS_GRADLE_VERBOSE $ENV{ROS_GRADLE_VERBOSE})
     if(ROS_GRADLE_VERBOSE)
-        set(GRADLE_CMD "./gradlew")
+        set(verbosity "--verbosity")
     else()
-        set(GRADLE_CMD "./gradlew;-q")
+        set(verbosity "")
     endif()
-    set(GEN_OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/generated_java_messages.flag)
 
-    add_custom_command(OUTPUT ${GEN_OUTPUT_FILE}
+    add_custom_target(${ARG_PKG}_generate_messages_java_gradle
+        COMMAND ${CATKIN_ENV} ${PYTHON_EXECUTABLE} ${GENJAVA_BIN}
+            ${verbosity}
+            --compile
+            -o ${GRADLE_BUILD_DIR}
+            -p ${ARG_PKG}
         DEPENDS ${GRADLE_BUILD_FILE} ${ARG_GENERATED_FILES}
-        COMMAND ${CATKIN_ENV} ${GRADLE_CMD}
-        COMMAND touch ${GEN_OUTPUT_FILE}
         WORKING_DIRECTORY ${GRADLE_BUILD_DIR}/${ARG_PKG}
-        COMMENT "Generating Java code for ${ARG_PKG}")
-    list(APPEND ALL_GEN_OUTPUT_FILES_java ${GEN_OUTPUT_FILE})
-
-    ################################
-    # Debugging
-    ################################
-    #foreach(gen_output_file ${ALL_GEN_OUTPUT_FILES_java})
-    #    message(STATUS "ALL_GEN_OUTPUT_FILES_java..........${gen_output_file}")
-    #endforeach()
+        COMMENT "Compiling Java code for ${ARG_PKG}"
+    )
+    add_dependencies(${ARG_PKG}_generate_messages ${ARG_PKG}_generate_messages_java_gradle)
 
     ################################
     # Dependent Targets
     ################################
+    # This is a bad hack that needs to disappear. e.g.
+    # - topic_tools and roscpp are both packages with a couple of msgs
+    # - topic tools messages doesn't actually depend on roscpp messages
+    # this is guarded, so it's not doubling up on work when called from catkin_package (roscpp does this too)
+    # and we need it to get access to the build_depends list just in case people called generate_messages before catkin_package()
+    if(NOT DEFINED ${ARG_PKG}_BUILD_DEPENDS)
+        catkin_package_xml(DIRECTORY ${PROJECT_SOURCE_DIR})
+    endif()
+    foreach(depends ${${ARG_PKG}_BUILD_DEPENDS})
+        if(TARGET ${depends}_generate_messages_java_gradle)
+            message(STATUS "Adding dependency.....${depends}_generate_messages -> ${ARG_PKG}_generate_messages")
+            add_dependencies(${ARG_PKG}_generate_messages_java_gradle ${depends}_generate_messages_java_gradle)
+        endif()
+    endforeach()
     # Make sure we have built gradle-rosjava_bootstrap if it is in the source workspace
     # (otherwise package.xml will make sure it has installed via rosdep/deb.
     #if(TARGET gradle-rosjava_bootstrap)
@@ -92,5 +113,12 @@ macro(_generate_module_java ARG_PKG ARG_GEN_OUTPUT_DIR ARG_GENERATED_FILES)
         # is not defined till after this module is parsed, so add it all
         #add_dependencies(${ARG_PKG}_generate_messages gradle-rosjava_bootstrap)
     #endif()
+
+    ################################
+    # Debugging
+    ################################
+    #foreach(gen_output_file ${ALL_GEN_OUTPUT_FILES_java})
+    #    message(STATUS "ALL_GEN_OUTPUT_FILES_java..........${gen_output_file}")
+    #endforeach()
 endmacro()
 
diff --git a/src/genjava/genjava_main.py b/src/genjava/genjava_main.py
index 43418d6..4305805 100644
--- a/src/genjava/genjava_main.py
+++ b/src/genjava/genjava_main.py
@@ -60,6 +60,8 @@ def parse_arguments(argv):
     #parser.add_argument('-m', '--message', action='store', help='the message file')
     parser.add_argument('-p', '--package', action='store', help='package to find the message file')
     parser.add_argument('-o', '--output-dir', action='store', help='output directory for the java code (e.g. build/foo_msgs)')
+    parser.add_argument('-c', '--compile', default=False, action='store_true', help='switch to compile mode (default is generating mode)')
+    parser.add_argument('-v', '--verbosity', default=False, action='store_true', help='enable verbosity in debugging (false)')
     #parser.add_argument('-I', '--include-path', action='append', help="include paths to the package and deps msg files")
     #myargs = rospy.myargv(argv=sys.argv)
     #return parser.parse_args(args=myargs[1:])
@@ -73,4 +75,7 @@ def parse_arguments(argv):
 def main(argv):
     args = parse_arguments(argv[1:])
     #print("genjava %s/%s" % (args.package, args.message))
-    gradle_project.create(args.package, args.output_dir)
+    if not args.compile:
+        gradle_project.create(args.package, args.output_dir)
+    else:
+        gradle_project.build(args.package, args.output_dir, args.verbosity)
diff --git a/src/genjava/genjava_main.pyc b/src/genjava/genjava_main.pyc
index 556d45fb04dfcf6d6b3d616f85af339e563a0c98..07cfc619d99a606c41854b70b93f6fa2bde78baf 100644
GIT binary patch
delta 571
zcmbQjb)Scw`7<xqwu03Y*%xtfGB7YWGcYm~&z`tB(4UDRg@+-9mm!6Zp@f+sg_R+N
zpCN^vAw__pnTeUPhLItQi6KRhAw>v7g)m$N3quV9Lo*{ou!hKHe#T{t^~FpK3=F!-
z#UQJ6b(8aR3o>(3OV}A07*bNx5=(PRO1Kyp7>Y~si&EoDib_+9jX~V<%#!2`g_3*)
zs0M}H{FGD$4X74{%wmP~)V$Q9#FEUsbg-Nz#GbNZZjg1lWvN9;`Nf$fl{&?$3=9mZ
zd5K9msS0pWh0HvKl+>is^mLGZjkLs^;#5ry*2&wMOgUK@7#Q3@0+U}eb=UJSFfcH%
z3Ngtr$}lQ1DzPLpGB7ZJyu<<vx*!Gyh7tylw^JAy<eM28Y8e?oVa3Q$Y{XE)#E``d
z=CXiER)%IK2F5%Yuml@e2qpp2!_Lsm%)pq!z!0nfvcoS^3S^xI2Ll5`5I@KsP`E*Z
zWb$=pZTS+AYm-Vdb5cq`0SxybSbGrfWKNcN2X9b-f{b8b6ky_Hlw{HXnF0>>`1rKa
hlG38o_;`>n7=l2mN<cmi0@(|;GDv*#5|(^MQ2;V}c_9D*

delta 216
zcmcc5Glh$t`7<w9@r+dy*%xuKGcYhXGcYm~hfmxb$j!`9!@$tY$Plc-vpJY?86%Sh
z%j6}@rjs8tcO`N#FfcH%3Ngtr%CICeGB7YOF)%PN!?bHLFff!bfV8JDGRQYGGSo6M
zlrS=6F)`FIGGsA>Nfw4?CI-e728Lh_kY2w`kSQ9h3=9lGJPZsBli66c*}*bFT$2M>
o<9R$87#NCKK-Mw}Oy18bEy@P5gn=Olq!X+uNO1Cd)_g``07M}noB#j-

diff --git a/src/genjava/gradle_project.py b/src/genjava/gradle_project.py
index e061038..2606903 100644
--- a/src/genjava/gradle_project.py
+++ b/src/genjava/gradle_project.py
@@ -8,7 +8,7 @@ from __future__ import print_function
 
 import os
 import shutil
-
+import subprocess
 from catkin_pkg.packages import find_packages
 import rospkg
 
@@ -98,7 +98,7 @@ def create_dependency_string(project_name, msg_package_index):
             dependency_package = msg_package_index[dep.name]
         except KeyError:
             continue  # it's not a message package
-        gradle_dependency_string += "compile 'org.ros.rosjava_messages:" + dependency_package.name + ":" + dependency_package.version + "'\n"
+        gradle_dependency_string += "  compile 'org.ros.rosjava_messages:" + dependency_package.name + ":" + dependency_package.version + "'\n"
     return gradle_dependency_string
 
 
@@ -120,7 +120,8 @@ def create_msg_package_index():
     ros_paths = [x for x in ros_paths.split(':') if x]
     for path in reversed(ros_paths):  # make sure we pick up the source overlays last
         for unused_package_path, package in find_packages(path).items():
-            if 'message_generation' in [dep.name for dep in package.build_depends]:
+            if ('message_generation' in [dep.name for dep in package.build_depends] or
+               'genmsg' in [dep.name for dep in package.build_depends]):
 #                 print(package.name)
 #                 print("  version: %s" % package.version)
 #                 print("  dependencies: ")
@@ -153,3 +154,17 @@ def create(msg_pkg_name, output_dir):
     pkg_directory = os.path.dirname(msg_package_index[msg_pkg_name].filename)
     msg_pkg_version = msg_package_index[msg_pkg_name].version
     populate_project(msg_pkg_name, msg_pkg_version, pkg_directory, genjava_gradle_dir, msg_dependencies)
+
+
+def build(msg_pkg_name, output_dir, verbosity):
+    droppings_file = os.path.join(output_dir, msg_pkg_name, 'droppings')
+    if not os.path.isfile(droppings_file):
+        #print("Someone already left droppings here! %s" % droppings_file)
+        return
+    print("Scooping the droppings! [%s]" % droppings_file)
+    os.remove(droppings_file)
+    cmd = ['./gradlew']
+    if not verbosity:
+        cmd.append('--quiet')
+    print("COMMAND........................%s" % cmd)
+    subprocess.call(cmd, stderr=subprocess.STDOUT,)
diff --git a/src/genjava/templates/genjava_project/build.gradle.in b/src/genjava/templates/genjava_project/build.gradle.in
index c0896ea..371d74f 100644
--- a/src/genjava/templates/genjava_project/build.gradle.in
+++ b/src/genjava/templates/genjava_project/build.gradle.in
@@ -55,8 +55,15 @@ task generateSources (type: JavaExec) {
 }
 
 dependencies {
-  compile 'org.ros.rosjava_bootstrap:message_generation:[0.1,)'
-  %(msg_dependencies)s
+    compile 'org.ros.rosjava_bootstrap:message_generation:[0.1,)'
+    %(msg_dependencies)s
+}
+
+jar {
+    manifest = osgiManifest {
+        classesDir = sourceSets.main.output.classesDir
+        classpath = configurations.runtime
+    }
 }
 
 task info << {
@@ -82,4 +89,18 @@ task info << {
     }
 }
 
+/* Damon's message generator doesn't catch every message. It expects everything to be nicely under 'msg'
+ * and that directory to be under the package root. It also expects every msg it finds should be buildable.
+ * It kinda works until now because it ignores any package which doesn't conform to this and those are just
+ * test packages (we hope).
+ *  
+ * Until we get this properly fixed (it fails in genjava), then we use the following bugfix to deal with the
+ * 'Could not copy MANIFEST.MF...' error that occurs when no sources are to be made for an artifact.
+ */
+task bugfixtask << {
+    mkdir sourceSets.main.output.classesDir
+}
+
+jar.dependsOn(bugfixtask)
+
 defaultTasks 'publishMavenJavaPublicationToMavenRepository'
-- 
GitLab