Building slycot from source.

Change-Id: I2e9df7a50749818bd4526161fbc50bca08e255e8
diff --git a/WORKSPACE b/WORKSPACE
index a37e1d4..999c66a 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -4,6 +4,18 @@
   build_file = 'debian/usr.BUILD',
 )
 
+new_git_repository(
+  name = 'slycot_repo',
+  remote = 'https://github.com/avventi/Slycot.git',
+  build_file = 'debian/slycot.BUILD',
+  commit = '5af5f283cb23cbe23c4dfea4d5e56071bdbd6e70',
+)
+
+bind(
+  name = 'slycot',
+  actual = '@slycot_repo//:slycot',
+)
+
 # TODO(brian): Make these point to something which isn't hard-coded to come off
 # the host system...
 bind(
diff --git a/debian/slycot.BUILD b/debian/slycot.BUILD
new file mode 100644
index 0000000..64eb358
--- /dev/null
+++ b/debian/slycot.BUILD
@@ -0,0 +1,96 @@
+# TODO(austin): I bet this is wrong.
+licenses(['restricted'])
+
+load('/tools/build_rules/fortran', 'fortran_library')
+
+# We can't create _wrapper.so in the slycot folder, and can't move it.
+# The best way I found to do this is to modify _wrapper.pyf to instead generate
+# a _fortranwrapper.so library, and then place a _wrapper.py file in slycot/
+# which loads _fortranwrapper from the correct location.  This means that I
+# don't need to modify the repository.
+genrule(
+  name = '_fortranwrapper_pyf',
+  srcs = ['slycot/src/_wrapper.pyf'],
+  outs = ['slycot/src/_fortranwrapper.pyf'],
+  cmd = 'cat $(SRCS) | sed \'s/_wrapper/_fortranwrapper/\' > $(OUTS)'
+)
+
+# Now generate the module wrapper.
+genrule(
+  name = '_fortranwrappermodule',
+  srcs = [
+    'slycot/src/analysis.pyf',
+    'slycot/src/synthesis.pyf',
+    'slycot/src/_fortranwrapper.pyf',
+    'slycot/src/math.pyf',
+    'slycot/src/transform.pyf',
+  ],
+  outs = ['_fortranwrappermodule.c'],
+  cmd = '/usr/bin/python /usr/bin/f2py $(location :slycot/src/_fortranwrapper.pyf) --include-paths external/slycot_repo/slycot/src/ --coutput $(OUTS)',
+)
+
+# Build it.
+cc_library(
+  name = 'slycot_c',
+  srcs = [
+    ':_fortranwrappermodule',
+  ],
+  deps = [
+    ':fortran_files',
+    '@usr_repo//:python2.7_lib',
+    '@usr_repo//:python2.7_f2py',
+  ],
+  copts = [
+    '-Wno-error',
+    '-Wno-incompatible-pointer-types-discards-qualifiers',
+    '-Wno-cast-align',
+    '-Wno-unused-parameter',
+    '-Wno-missing-field-initializers',
+    '-Wno-unused-function',
+  ],
+)
+
+# Now actually build the fortran files.
+fortran_library(
+  name = 'fortran_files',
+  srcs = glob(['slycot/src/*.f']),
+)
+
+# Link it all together.  Make sure it is dynamically linked since I don't know
+# how to build the fortran files in statically to a single .so yet, and I'm not
+# sure bazel does either.
+cc_binary(
+  name = '_fortranwrapper.so',
+  deps = [
+    ':fortran_files',
+    ':slycot_c',
+  ],
+  linkopts = ['-shared', '-lblas', '-llapack'],
+  linkstatic=0,
+)
+
+# Generate the _wrapper file which loads _fortranwrapper and pretends.
+genrule(
+  name = '_wrapper',
+  outs = ['slycot/_wrapper.py'],
+  cmd = 'echo "from _fortranwrapper import *" > $(OUTS)',
+  output_to_bindir=1,
+)
+
+# Now present a python library for slycot
+py_library(
+  name = 'slycot',
+  srcs = [
+    'slycot/analysis.py',
+    'slycot/examples.py',
+    'slycot/__init__.py',
+    'slycot/math.py',
+    'slycot/synthesis.py',
+    'slycot/transform.py',
+    ':_wrapper',
+  ],
+  data = [
+    ':_fortranwrapper.so',
+  ],
+  visibility = ['//visibility:public'],
+)
diff --git a/debian/usr.BUILD b/debian/usr.BUILD
index e50da1a..ac354cc 100644
--- a/debian/usr.BUILD
+++ b/debian/usr.BUILD
@@ -24,3 +24,64 @@
 cc_library(
   name = 'libpthread',
 )
+
+cc_library(
+  name = 'python3.4_lib',
+  hdrs = glob(['include/python3.4m/**/*.h']),
+  includes = [
+    'include/python3.4m/',
+  ],
+  visibility = ['//visibility:public'],
+)
+
+cc_library(
+  name = 'python3.4_f2py',
+  srcs = [
+    'lib/python3/dist-packages/numpy/f2py/src/fortranobject.c',
+  ],
+  hdrs = [
+    'lib/python3/dist-packages/numpy/f2py/src/fortranobject.h',
+  ],
+  copts = [
+    '-Wno-error',
+  ],
+  includes = [
+    'lib/python3/dist-packages/numpy/f2py/src/',
+  ],
+  deps = [
+    ':python3.4_lib',
+  ],
+  visibility = ['//visibility:public'],
+)
+
+cc_library(
+  name = 'python2.7_lib',
+  hdrs = glob(['include/python2.7/**/*.h']),
+  srcs = [
+    'lib/x86_64-linux-gnu/libpython2.7.so',
+  ],
+  includes = [
+    'include/python2.7/',
+  ],
+  visibility = ['//visibility:public'],
+)
+
+cc_library(
+  name = 'python2.7_f2py',
+  srcs = [
+    'lib/python2.7/dist-packages/numpy/f2py/src/fortranobject.c',
+  ],
+  hdrs = [
+    'lib/python2.7/dist-packages/numpy/f2py/src/fortranobject.h',
+  ],
+  copts = [
+    '-Wno-error',
+  ],
+  includes = [
+    'lib/python2.7/dist-packages/numpy/f2py/src/',
+  ],
+  deps = [
+    ':python2.7_lib',
+  ],
+  visibility = ['//visibility:public'],
+)
diff --git a/frc971/control_loops/python/BUILD b/frc971/control_loops/python/BUILD
index 747b49c..b79d676 100644
--- a/frc971/control_loops/python/BUILD
+++ b/frc971/control_loops/python/BUILD
@@ -8,4 +8,7 @@
     'polytope.py',
     'libcdd.py',
   ],
+  deps = [
+    '//external:slycot',
+  ],
 )
diff --git a/tools/build_rules/fortran.bzl b/tools/build_rules/fortran.bzl
new file mode 100644
index 0000000..4de4430
--- /dev/null
+++ b/tools/build_rules/fortran.bzl
@@ -0,0 +1,78 @@
+def _single_fortran_object_impl(ctx):
+  toolchain_cflags = (ctx.fragments.cpp.compiler_options([]) +
+      ctx.fragments.cpp.c_options +
+      ctx.fragments.cpp.unfiltered_compiler_options([]) + ['-fPIC'])
+
+  cmd = toolchain_cflags + ['-c', ctx.file.src.path, '-o', ctx.outputs.pic_o.path]
+  filtered_cmd = []
+  # Strip out the C/C++ specific flags.
+  exclude_flags = ['-fcolor-diagnostics',
+                   '-Wswitch-enum',
+                   '-Wpointer-arith',
+                   '-Wcast-qual',
+                   '-Wwrite-strings',
+                   '-Wsign-compare',
+                   '-Wformat=2',
+                   '-Werror',
+                   '-Wno-builtin-macro-redefined',
+                   '-D__has_feature(x)=0']
+
+  for flag in cmd:
+    if flag not in exclude_flags:
+      filtered_cmd.append(flag)
+
+  ctx.action(
+    inputs = [ctx.file.src],
+    outputs = [ctx.outputs.pic_o],
+    mnemonic = "Fortran",
+    executable = ctx.fragments.cpp.compiler_executable,
+    arguments = filtered_cmd,
+    progress_message = 'Building %s' % ctx.outputs.pic_o.short_path,
+  )
+
+def _define_fortran_output(attrs):
+  if not attrs.src.name.endswith('.f'):
+    fail('Fortran files must end in \'.f\'', 'src')
+
+  fortran_file_base = attrs.src.name[:-2]
+  return {
+    'pic_o': fortran_file_base + '.pic.o',
+  }
+
+
+_single_fortran_object = rule(
+  implementation = _single_fortran_object_impl,
+  attrs = {
+    'src': attr.label(single_file=True, allow_files=FileType(['.f'])),
+    'cc_libs': attr.label_list(providers=['cc']),
+  },
+  outputs = _define_fortran_output,
+  fragments = [
+    'cpp',
+  ],
+)
+
+def fortran_library(name, srcs, deps = [], visibility = None):
+  """Builds a shared library from a set of fortran files.
+
+  Args:
+    srcs: list of fortran files ending in .f
+    deps: cc_library or fortran_library dependencies.
+  """
+  pic_o_files = []
+  for src in srcs:
+    pic_o_file = src[:-2] + '.pic.o'
+    _single_fortran_object(name=name + '_' + pic_o_file,
+                           src=src,
+                           visibility=['//visibility:private'])
+    pic_o_files.append(pic_o_file)
+
+  native.cc_library(
+    name = name,
+    deps = deps,
+    srcs = pic_o_files,
+    linkopts = [
+      '-lgfortran',
+    ],
+    visibility = visibility,
+  )