$search
00001 #!/usr/bin/env python 00002 # Software License Agreement (BSD License) 00003 # 00004 # Copyright (c) 2009, Willow Garage, Inc. 00005 # All rights reserved. 00006 # 00007 # Redistribution and use in source and binary forms, with or without 00008 # modification, are permitted provided that the following conditions 00009 # are met: 00010 # 00011 # * Redistributions of source code must retain the above copyright 00012 # notice, this list of conditions and the following disclaimer. 00013 # * Redistributions in binary form must reproduce the above 00014 # copyright notice, this list of conditions and the following 00015 # disclaimer in the documentation and/or other materials provided 00016 # with the distribution. 00017 # * Neither the name of Willow Garage, Inc. nor the names of its 00018 # contributors may be used to endorse or promote products derived 00019 # from this software without specific prior written permission. 00020 # 00021 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 # POSSIBILITY OF SUCH DAMAGE. 00033 # 00034 00035 ## ROS message source code generation for C++ 00036 ## 00037 ## Converts ROS .msg files in a package into C++ source code implementations. 00038 00039 import roslib; roslib.load_manifest('roscpp') 00040 import roscpp.msg_gen as genmsg_cpp 00041 00042 import sys 00043 import os 00044 import traceback 00045 00046 # roslib.msgs contains the utilities for parsing .msg specifications. It is meant to have no rospy-specific knowledge 00047 import roslib.srvs 00048 import roslib.packages 00049 import roslib.gentools 00050 00051 try: 00052 from cStringIO import StringIO #Python 2.x 00053 except ImportError: 00054 from io import StringIO #Python 3.x 00055 00056 def write_begin(s, spec, file): 00057 """ 00058 Writes the beginning of the header file: a comment saying it's auto-generated and the include guards 00059 00060 @param s: The stream to write to 00061 @type s: stream 00062 @param spec: The spec 00063 @type spec: roslib.srvs.SrvSpec 00064 @param file: The file this service is being generated for 00065 @type file: str 00066 """ 00067 s.write("/* Auto-generated by genmsg_cpp for file %s */\n"%(file)) 00068 s.write('#ifndef %s_SERVICE_%s_H\n'%(spec.package.upper(), spec.short_name.upper())) 00069 s.write('#define %s_SERVICE_%s_H\n'%(spec.package.upper(), spec.short_name.upper())) 00070 00071 def write_end(s, spec): 00072 """ 00073 Writes the end of the header file: the ending of the include guards 00074 00075 @param s: The stream to write to 00076 @type s: stream 00077 @param spec: The spec 00078 @type spec: roslib.srvs.SrvSpec 00079 """ 00080 s.write('#endif // %s_SERVICE_%s_H\n'%(spec.package.upper(), spec.short_name.upper())) 00081 00082 def write_generic_includes(s): 00083 """ 00084 Writes the includes that all service need 00085 00086 @param s: The stream to write to 00087 @type s: stream 00088 """ 00089 s.write('#include "ros/service_traits.h"\n\n') 00090 00091 def write_trait_char_class(s, class_name, cpp_msg, value): 00092 """ 00093 Writes a class trait for traits which have static value() members that return const char* 00094 00095 e.g. write_trait_char_class(s, "MD5Sum", "std_srvs::Empty", "hello") yields: 00096 template<> 00097 struct MD5Sum<std_srvs::Empty> 00098 { 00099 static const char* value() { return "hello"; } 00100 static const char* value(const std_srvs::Empty&) { return value(); } 00101 }; 00102 00103 @param s: The stream to write to 00104 @type s: stream 00105 @param class_name: The name of the trait class 00106 @type class_name: str 00107 @param cpp_msg: The C++ message declaration, e.g. "std_srvs::Empty" 00108 @type cpp_msg: str 00109 @param value: The string value to return from the value() function 00110 @type value: str 00111 """ 00112 s.write('template<>\nstruct %s<%s> {\n'%(class_name, cpp_msg)) 00113 s.write(' static const char* value() \n {\n return "%s";\n }\n\n'%(value)) 00114 s.write(' static const char* value(const %s&) { return value(); } \n'%(cpp_msg)) 00115 s.write('};\n\n') 00116 00117 def write_traits(s, spec, cpp_name_prefix): 00118 """ 00119 Write all the service traits for a message 00120 00121 @param s: The stream to write to 00122 @type s: stream 00123 @param spec: The service spec 00124 @type spec: roslib.srvs.SrvSpec 00125 @param cpp_name_prefix: The C++ prefix to prepend when referencing the service, e.g. "std_srvs::" 00126 @type cpp_name_prefix: str 00127 """ 00128 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package) 00129 md5sum = roslib.gentools.compute_md5(gendeps_dict) 00130 00131 s.write('namespace ros\n{\n') 00132 s.write('namespace service_traits\n{\n') 00133 00134 request_with_allocator = '%s%s_<ContainerAllocator> '%(cpp_name_prefix, spec.request.short_name) 00135 response_with_allocator = '%s%s_<ContainerAllocator> '%(cpp_name_prefix, spec.response.short_name) 00136 00137 write_trait_char_class(s, 'MD5Sum', '%s%s'%(cpp_name_prefix, spec.short_name), md5sum); 00138 write_trait_char_class(s, 'DataType', '%s%s'%(cpp_name_prefix, spec.short_name), spec.full_name); 00139 genmsg_cpp.write_trait_char_class(s, 'MD5Sum', request_with_allocator, md5sum) 00140 genmsg_cpp.write_trait_char_class(s, 'DataType', request_with_allocator, spec.full_name) 00141 genmsg_cpp.write_trait_char_class(s, 'MD5Sum', response_with_allocator, md5sum) 00142 genmsg_cpp.write_trait_char_class(s, 'DataType', response_with_allocator, spec.full_name) 00143 s.write('} // namespace service_traits\n') 00144 s.write('} // namespace ros\n\n') 00145 00146 def generate(srv_path): 00147 """ 00148 Generate a service 00149 00150 @param srv_path: the path to the .srv file 00151 @type srv_path: str 00152 """ 00153 (package_dir, package) = roslib.packages.get_dir_pkg(srv_path) 00154 (_, spec) = roslib.srvs.load_from_file(srv_path, package) 00155 00156 s = StringIO() 00157 cpp_prefix = '%s::'%(package) 00158 write_begin(s, spec, srv_path) 00159 genmsg_cpp.write_generic_includes(s) 00160 write_generic_includes(s) 00161 genmsg_cpp.write_includes(s, spec.request) 00162 s.write('\n') 00163 genmsg_cpp.write_includes(s, spec.response) 00164 00165 gendeps_dict = roslib.gentools.get_dependencies(spec, spec.package) 00166 md5sum = roslib.gentools.compute_md5(gendeps_dict) 00167 00168 s.write('namespace %s\n{\n'%(package)) 00169 genmsg_cpp.write_struct(s, spec.request, cpp_prefix, {'ServerMD5Sum': md5sum}) 00170 s.write('\n') 00171 genmsg_cpp.write_struct(s, spec.response, cpp_prefix, {'ServerMD5Sum': md5sum}) 00172 s.write('struct %s\n{\n'%(spec.short_name)) 00173 s.write('\n') 00174 s.write('typedef %s Request;\n'%(spec.request.short_name)) 00175 s.write('typedef %s Response;\n'%(spec.response.short_name)) 00176 s.write('Request request;\n') 00177 s.write('Response response;\n\n') 00178 s.write('typedef Request RequestType;\n') 00179 s.write('typedef Response ResponseType;\n') 00180 s.write('}; // struct %s\n'%(spec.short_name)) 00181 s.write('} // namespace %s\n\n'%(package)) 00182 00183 request_cpp_name = "Request" 00184 response_cpp_name = "Response" 00185 genmsg_cpp.write_traits(s, spec.request, cpp_prefix) 00186 s.write('\n') 00187 genmsg_cpp.write_traits(s, spec.response, cpp_prefix) 00188 genmsg_cpp.write_serialization(s, spec.request, cpp_prefix) 00189 s.write('\n') 00190 genmsg_cpp.write_serialization(s, spec.response, cpp_prefix) 00191 00192 write_traits(s, spec, cpp_prefix) 00193 00194 write_end(s, spec) 00195 00196 output_dir = '%s/srv_gen/cpp/include/%s'%(package_dir, package) 00197 if (not os.path.exists(output_dir)): 00198 # if we're being run concurrently, the above test can report false but os.makedirs can still fail if 00199 # another copy just created the directory 00200 try: 00201 os.makedirs(output_dir) 00202 except OSError as e: 00203 pass 00204 00205 f = open('%s/%s.h'%(output_dir, spec.short_name), 'w') 00206 f.write(s.getvalue() + "\n") 00207 00208 s.close() 00209 00210 def generate_services(argv): 00211 for arg in argv[1:]: 00212 generate(arg) 00213 00214 if __name__ == "__main__": 00215 roslib.msgs.set_verbose(False) 00216 generate_services(sys.argv) 00217 00218