ovs-dev.py: Add support for clang builds.
[sliver-openvswitch.git] / utilities / ovs-dev.py
1 #!/usr/bin/python
2 # Copyright (c) 2013 Nicira, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import optparse
17 import os
18 import shutil
19 import subprocess
20 import sys
21 import tempfile
22
23 ENV = os.environ
24 HOME = ENV["HOME"]
25 OVS_SRC = HOME + "/ovs"
26 ROOT = HOME + "/root"
27 PATH = "%(ovs)s/utilities:%(ovs)s/ovsdb:%(ovs)s/vswitchd" % {"ovs": OVS_SRC}
28
29 ENV["CFLAGS"] = "-g -O0"
30 ENV["PATH"] = PATH + ":" + ENV["PATH"]
31
32 options = None
33 parser = None
34 commands = []
35
36
37 def _sh(*args, **kwargs):
38     print "------> " + " ".join(args)
39     shell = len(args) == 1
40     if kwargs.get("capture", False):
41         proc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
42         return proc.stdout.readlines()
43     elif kwargs.get("check", True):
44         subprocess.check_call(args, shell=shell)
45     else:
46         subprocess.call(args, shell=shell)
47
48
49 def uname():
50     return _sh("uname", "-r", capture=True)[0].strip()
51
52
53 def conf():
54     tag()
55     if options.clang:
56         ENV["CC"] = "clang"
57
58     configure = ["./configure", "--prefix=" + ROOT, "--localstatedir=" + ROOT,
59                  "--with-logdir=%s/log" % ROOT, "--with-rundir=%s/run" % ROOT,
60                  "--with-linux=/lib/modules/%s/build" % uname(),
61                  "--with-dbdir=" + ROOT]
62
63     if options.werror:
64         configure.append("--enable-Werror")
65
66     if options.cache_time:
67         configure.append("--enable-cache-time")
68
69     if options.mandir:
70         configure.append("--mandir=" + options.mandir)
71
72     _sh("./boot.sh")
73     _sh(*configure)
74 commands.append(conf)
75
76
77 def make(args=""):
78     make = "make -s -j 8 " + args
79     try:
80         _sh("cgcc", "--version", capture=True)
81         # XXX: For some reason the clang build doesn't place nicely with
82         # sparse.  At some point this needs to be figured out and this check
83         # removed.
84         if not options.clang:
85             make += " C=1"
86     except OSError:
87         pass
88     _sh(make)
89 commands.append(make)
90
91
92 def check():
93     make("check")
94 commands.append(check)
95
96
97 def tag():
98     ctags = ['ctags', '-R', '-f', '.tags']
99
100     try:
101         _sh(*(ctags + ['--exclude="datapath/"']))
102     except:
103         try:
104             _sh(*ctags)  # Some versions of ctags don't have --exclude
105         except:
106             pass
107
108     try:
109         _sh('cscope', '-R', '-b')
110     except:
111         pass
112 commands.append(tag)
113
114
115 def kill():
116     for proc in ["ovs-vswitchd", "ovsdb-server"]:
117         if os.path.exists("%s/run/openvswitch/%s.pid" % (ROOT, proc)):
118             _sh("ovs-appctl", "-t", proc, "exit", check=False)
119             time.sleep(.1)
120         _sh("sudo", "killall", "-q", "-2", proc, check=False)
121 commands.append(kill)
122
123
124 def reset():
125     kill()
126     if os.path.exists(ROOT):
127         shutil.rmtree(ROOT)
128     for dp in _sh("ovs-dpctl dump-dps", capture=True):
129         _sh("ovs-dpctl", "del-dp", dp.strip())
130 commands.append(reset)
131
132
133 def run():
134     kill()
135     for d in ["log", "run"]:
136         d = "%s/%s" % (ROOT, d)
137         shutil.rmtree(d, ignore_errors=True)
138         os.makedirs(d)
139
140     pki_dir = ROOT + "/pki"
141     if not os.path.exists(pki_dir):
142         os.mkdir(pki_dir)
143         os.chdir(pki_dir)
144         _sh("ovs-pki init")
145         _sh("ovs-pki req+sign ovsclient")
146         os.chdir(OVS_SRC)
147
148     if not os.path.exists(ROOT + "/conf.db"):
149         _sh("ovsdb-tool", "create", ROOT + "/conf.db",
150             OVS_SRC + "/vswitchd/vswitch.ovsschema")
151
152     opts = ["--pidfile", "--log-file", "--enable-dummy"]
153
154     _sh(*(["ovsdb-server",
155            "--remote=punix:%s/run/db.sock" % ROOT,
156            "--remote=db:Open_vSwitch,Open_vSwitch,manager_options",
157            "--private-key=db:Open_vSwitch,SSL,private_key",
158            "--certificate=db:Open_vSwitch,SSL,certificate",
159            "--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert",
160            "--detach", "-vconsole:off"] + opts))
161
162     _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" \
163         " %s/ovsclient-cert.pem %s/vswitchd.cacert"
164         % (pki_dir, pki_dir, pki_dir))
165     version = _sh("ovs-vsctl --no-wait --version", capture=True)
166     version = version[0].strip().split()[3]
167     root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch",
168                     capture=True)[0].strip()
169     _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s"
170         % (root_uuid, version))
171
172     cmd = [OVS_SRC + "/vswitchd/ovs-vswitchd"]
173     if options.gdb:
174         cmd = ["gdb", "--args"] + cmd
175     elif options.valgrind:
176         cmd = ["valgrind", "--track-origins=yes"] + cmd
177     else:
178         cmd = ["sudo"] + cmd
179         opts = opts + ["-vconsole:off", "--detach"]
180     _sh(*(cmd + opts))
181 commands.append(run)
182
183
184 def modinst():
185     if not os.path.exists("/lib/modules"):
186         print "Missing modules directory.  Is this a Linux system?"
187         sys.exit(1)
188
189     try:
190         _sh("rmmod", "openvswitch")
191     except subprocess.CalledProcessError, e:
192         pass  # Module isn't loaded
193
194     try:
195         _sh("rm /lib/modules/%s/extra/openvswitch.ko" % uname())
196     except subprocess.CalledProcessError, e:
197         pass  # Module isn't installed
198
199     conf()
200     make()
201     make("modules_install")
202
203     _sh("modprobe", "openvswitch")
204     _sh("dmesg | grep openvswitch | tail -1")
205 commands.append(modinst)
206
207
208 def env():
209     print "export PATH=" + ENV["PATH"]
210 commands.append(env)
211
212
213 def doc():
214     parser.print_help()
215     print \
216 """
217 This program is designed to help developers build and run Open vSwitch without
218 necessarily needing to know the gory details. Given some basic requirements
219 (described below), it can be used to build and run Open vSwitch, keeping
220 runtime files in the user's home directory.
221
222 Basic Configuration:
223     # This section can be run as a script on ubuntu systems.
224
225     # First install the basic requirements needed to build Open vSwitch.
226     sudo apt-get install git build-essential libtool autoconf pkg-config \\
227             libssl-dev pkg-config gdb linux-headers-`uname -r`
228
229     # Next clone the Open vSwitch source.
230     git clone git://git.openvswitch.org/openvswitch %(ovs)s
231
232     # Setup environment variables.
233     `%(v)s env`
234
235     # Build the switch.
236     %(v)s conf make
237
238     # Install the kernel module
239     sudo insmod %(ovs)s/datapath/linux/openvswitch.ko
240
241     # Run the switch.
242     %(v)s run
243
244 Commands:
245     conf    - Configure the ovs source.
246     make    - Build the source (must have been configured).
247     check   - Run the unit tests.
248     tag     - Run ctags and cscope over the source.
249     kill    - Kill all running instances of ovs.
250     reset   - Reset any runtime configuration in %(run)s.
251     run     - Run ovs.
252     modinst - Build ovs and install the kernel module.
253     env     - Print the required path environment variable.
254     doc     - Print this message.
255 """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": ROOT}
256     sys.exit(0)
257 commands.append(doc)
258
259
260 def main():
261     global options
262     global parser
263
264     description = "Open vSwitch developer configuration. Try `%prog doc`."
265     cmd_names = [c.__name__ for c in commands]
266     parser = optparse.OptionParser(usage="usage: %prog"
267                                    + " [options] [%s] ..."
268                                    % "|".join(cmd_names),
269                                    description=description)
270
271     group = optparse.OptionGroup(parser, "conf")
272     group.add_option("--disable-Werror", dest="werror", action="store_false",
273                      default=True, help="compile without the Werror flag")
274     group.add_option("--cache-time", dest="cache_time",
275                      action="store_true", help="configure with cached timing")
276     group.add_option("--mandir", dest="mandir", metavar="MANDIR",
277                      help="configure the man documentation install directory")
278     parser.add_option_group(group)
279
280     group = optparse.OptionGroup(parser, "run")
281     group.add_option("-g", "--gdb", dest="gdb", action="store_true",
282                      help="run ovs-vswitchd under gdb")
283     group.add_option("--valgrind", dest="valgrind", action="store_true",
284                      help="run ovs-vswitchd under valgrind")
285     group.add_option("--clang", dest="clang", action="store_true",
286                      help="build ovs-vswitchd with clang")
287     parser.add_option_group(group)
288
289     options, args = parser.parse_args()
290
291     for arg in args:
292         if arg not in cmd_names:
293             print "Unknown argument " + arg
294             doc()
295
296     try:
297         os.chdir(OVS_SRC)
298     except OSError:
299         print "Missing %s." % OVS_SRC
300         doc()
301
302     for arg in args:
303         for cmd in commands:
304             if arg == cmd.__name__:
305                 cmd()
306
307
308 if __name__ == '__main__':
309     main()