diff --git a/cmake/genjava-extras.cmake.em b/cmake/genjava-extras.cmake.em index f08631de343a63d6c26c4ad5753cd015eabc1847..dd6ed36c26728d8b21784b2a6cff352055228190 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 43418d65b9641f599c8d1d85d886474edca5837f..4305805a2883fa170eccbf023ead331c61c9aa6e 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 Binary files a/src/genjava/genjava_main.pyc and b/src/genjava/genjava_main.pyc differ diff --git a/src/genjava/gradle_project.py b/src/genjava/gradle_project.py index e061038d0bd6a04335ff6080c894f484ecacb36a..260690326ecfd83a6a06d3f5693c2c6ce2b592ed 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 c0896ea326e38648dd01345806e55256d955ba11..371d74f4c8465ac0055a389dca989e4b72840560 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'