Add python packaging for the bpf library
authorBrenden Blanco <bblanco@plumgrid.com>
Mon, 8 Jun 2015 05:32:33 +0000 (22:32 -0700)
committerBrenden Blanco <bblanco@plumgrid.com>
Mon, 8 Jun 2015 05:34:58 +0000 (22:34 -0700)
* Add tagging/git support
* Reorganize bpf py lib to be more pythonic
* Add pip installable builders

Signed-off-by: Brenden Blanco <bblanco@plumgrid.com>
12 files changed:
CMakeLists.txt
scripts/CMakeLists.txt [new file with mode: 0644]
scripts/GetGitRevisionDescription.cmake [new file with mode: 0644]
scripts/GetGitRevisionDescription.cmake.in [new file with mode: 0644]
src/CMakeLists.txt
src/cc/CMakeLists.txt
src/python/CMakeLists.txt [new file with mode: 0644]
src/python/MANIFEST [new file with mode: 0644]
src/python/bpf/__init__.py [moved from src/bpf.py with 97% similarity]
src/python/setup.py.in [new file with mode: 0644]
tests/cc/test_call1.py
tests/wrapper.sh.in

index 49406c3..7e82f10 100644 (file)
@@ -7,6 +7,8 @@ set(CMAKE_BUILD_TYPE Debug)
 
 enable_testing()
 
+include(scripts/GetGitRevisionDescription.cmake)
+
 find_package(BISON)
 find_package(FLEX)
 find_package(LLVM REQUIRED CONFIG)
@@ -31,5 +33,6 @@ find_library(libclangSerialization NAMES clangSerialization HINTS ${CLANG_SEARCH
 set(CMAKE_C_FLAGS "-Wall")
 set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
 
+add_subdirectory(scripts)
 add_subdirectory(src)
 add_subdirectory(tests)
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5b0b792
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright (c) PLUMgrid, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+get_git_head_revision(GIT_REFSPEC GIT_SHA1)
+string(SUBSTRING "${GIT_SHA1}" 0 8 GIT_SHA1_SHORT)
+git_describe(GIT_DESCRIPTION)
+git_describe(GIT_TAG_LAST "--abbrev=0")
+git_get_exact_tag(GIT_TAG_EXACT)
+set(REVISION "${GIT_TAG_LAST}-${GIT_SHA1_SHORT}")
+if(GIT_TAG_EXACT)
+  string(SUBSTRING "${GIT_TAG_EXACT}" 1 -1 REVISION)
+  message(STATUS "Currently on Git tag ${GIT_TAG_EXACT}")
+else ()
+  message(STATUS "Latest recognized Git tag is ${GIT_TAG_LAST}")
+  set(GIT_TAG_EXACT "")
+endif()
+message(STATUS "Git HEAD is ${GIT_SHA1}")
+
+# strip leading 'v', and make unique for the tag
+message(STATUS "Revision is ${REVISION}")
+set(REVISION "${REVISION}" PARENT_SCOPE)
diff --git a/scripts/GetGitRevisionDescription.cmake b/scripts/GetGitRevisionDescription.cmake
new file mode 100644 (file)
index 0000000..1bf0230
--- /dev/null
@@ -0,0 +1,123 @@
+# - Returns a version string from Git
+#
+# These functions force a re-configure on each git commit so that you can
+# trust the values of the variables in your build system.
+#
+#  get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
+#
+# Returns the refspec and sha hash of the current head revision
+#
+#  git_describe(<var> [<additional arguments to git describe> ...])
+#
+# Returns the results of git describe on the source tree, and adjusting
+# the output so that it tests false if an error occurs.
+#
+#  git_get_exact_tag(<var> [<additional arguments to git describe> ...])
+#
+# Returns the results of git describe --exact-match on the source tree,
+# and adjusting the output so that it tests false if there was no exact
+# matching tag.
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+if(__get_git_revision_description)
+       return()
+endif()
+set(__get_git_revision_description YES)
+
+# We must run the following at "include" time, not at function call time,
+# to find the path to this module rather than the path to a calling list file
+get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
+
+function(get_git_head_revision _refspecvar _hashvar)
+       set(GIT_PARENT_DIR "${CMAKE_SOURCE_DIR}")
+       set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+       while(NOT EXISTS "${GIT_DIR}")  # .git dir not found, search parent directories
+               set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
+               get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
+               if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
+                       # We have reached the root directory, we are not in git
+                       set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+                       set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
+                       return()
+               endif()
+               set(GIT_DIR "${GIT_PARENT_DIR}/.git")
+       endwhile()
+       set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
+       if(NOT EXISTS "${GIT_DATA}")
+               file(MAKE_DIRECTORY "${GIT_DATA}")
+       endif()
+
+       if(NOT EXISTS "${GIT_DIR}/HEAD")
+               return()
+       endif()
+       set(HEAD_FILE "${GIT_DATA}/HEAD")
+       configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
+
+       configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
+               "${GIT_DATA}/grabRef.cmake"
+               @ONLY)
+       include("${GIT_DATA}/grabRef.cmake")
+
+       set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
+       set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
+endfunction()
+
+function(git_describe _var)
+       if(NOT GIT_FOUND)
+               find_package(Git QUIET)
+       endif()
+       get_git_head_revision(refspec hash)
+       if(NOT GIT_FOUND)
+               set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
+               return()
+       endif()
+       if(NOT hash)
+               set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
+               return()
+       endif()
+
+       # TODO sanitize
+       #if((${ARGN}" MATCHES "&&") OR
+       #       (ARGN MATCHES "||") OR
+       #       (ARGN MATCHES "\\;"))
+       #       message("Please report the following error to the project!")
+       #       message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
+       #endif()
+
+       #message(STATUS "Arguments to execute_process: ${ARGN}")
+
+       execute_process(COMMAND
+               "${GIT_EXECUTABLE}"
+               describe
+               ${hash}
+               ${ARGN}
+               WORKING_DIRECTORY
+               "${CMAKE_SOURCE_DIR}"
+               RESULT_VARIABLE
+               res
+               OUTPUT_VARIABLE
+               out
+               ERROR_QUIET
+               OUTPUT_STRIP_TRAILING_WHITESPACE)
+       if(NOT res EQUAL 0)
+               set(out "${out}-${res}-NOTFOUND")
+       endif()
+
+       set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
+
+function(git_get_exact_tag _var)
+       git_describe(out --exact-match ${ARGN})
+       set(${_var} "${out}" PARENT_SCOPE)
+endfunction()
diff --git a/scripts/GetGitRevisionDescription.cmake.in b/scripts/GetGitRevisionDescription.cmake.in
new file mode 100644 (file)
index 0000000..6faa374
--- /dev/null
@@ -0,0 +1,38 @@
+#
+# Internal file for GetGitRevisionDescription.cmake
+#
+# Requires CMake 2.6 or newer (uses the 'function' command)
+#
+# Original Author:
+# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
+# http://academic.cleardefinition.com
+# Iowa State University HCI Graduate Program/VRAC
+#
+# Copyright Iowa State University 2009-2010.
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+set(HEAD_HASH)
+
+file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
+
+string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
+if(HEAD_CONTENTS MATCHES "ref")
+       # named branch
+       string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
+       if(EXISTS "@GIT_DIR@/${HEAD_REF}")
+               configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+       elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
+               configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
+               set(HEAD_HASH "${HEAD_REF}")
+       endif()
+else()
+       # detached HEAD
+       configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
+endif()
+
+if(NOT HEAD_HASH)
+       file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
+       string(STRIP "${HEAD_HASH}" HEAD_HASH)
+endif()
index b011bbc..475dc7e 100644 (file)
@@ -10,3 +10,4 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
 include_directories(${CMAKE_CURRENT_BINARY_DIR})
 
 add_subdirectory(cc)
+add_subdirectory(python)
index 287336c..1c5c460 100644 (file)
@@ -26,3 +26,5 @@ set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${
 
 # Link against LLVM libraries
 target_link_libraries(bpfprog ${clang_libs} ${llvm_libs} LLVMBPFCodeGen)
+
+install(TARGETS bpfprog LIBRARY DESTINATION lib)
diff --git a/src/python/CMakeLists.txt b/src/python/CMakeLists.txt
new file mode 100644 (file)
index 0000000..891693e
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (c) PLUMgrid, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+
+macro(symlink_file SRC DST)
+  execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink ${SRC} ${DST})
+endmacro()
+
+symlink_file(${CMAKE_CURRENT_SOURCE_DIR}/bpf ${CMAKE_CURRENT_BINARY_DIR}/bpf)
+
+configure_file(setup.py.in ${CMAKE_CURRENT_BINARY_DIR}/setup.py @ONLY)
+# build the pip installable
+add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dist/bpf-${REVISION}.tar.gz
+  COMMAND python setup.py sdist
+  WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+  DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bpf/__init__.py ${CMAKE_CURRENT_BINARY_DIR}/setup.py
+  )
+add_custom_target(bpf_py ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/dist/bpf-${REVISION}.tar.gz)
+install(CODE "execute_process(COMMAND python setup.py install -f
+  --prefix=${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})")
diff --git a/src/python/MANIFEST b/src/python/MANIFEST
new file mode 100644 (file)
index 0000000..0f50437
--- /dev/null
@@ -0,0 +1,3 @@
+# file GENERATED by distutils, do NOT edit
+setup.py
+bpf/__init__.py
similarity index 97%
rename from src/bpf.py
rename to src/python/bpf/__init__.py
index f141b61..afbe564 100644 (file)
@@ -1,11 +1,11 @@
 # Copyright 2015 PLUMgrid
-# 
+#
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 # http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -121,17 +121,17 @@ class BPF(object):
                 raise StopIteration()
             return next_key
 
-    def __init__(self, dp_file="", dph_file="", text=None, debug=0):
+    def __init__(self, src_file="", hdr_file="", text=None, debug=0):
         self.debug = debug
         self.funcs = {}
         if text:
             self.module = lib.bpf_module_create_from_string(text.encode("ascii"), self.debug)
         else:
-            self.module = lib.bpf_module_create(dp_file.encode("ascii"),
-                    dph_file.encode("ascii"), self.debug)
+            self.module = lib.bpf_module_create(src_file.encode("ascii"),
+                    hdr_file.encode("ascii"), self.debug)
 
         if self.module == None:
-            raise Exception("Failed to compile BPF module %s" % dp_file)
+            raise Exception("Failed to compile BPF module %s" % src_file)
 
     def load_func(self, func_name, prog_type):
         if lib.bpf_function_start(self.module, func_name.encode("ascii")) == None:
diff --git a/src/python/setup.py.in b/src/python/setup.py.in
new file mode 100644 (file)
index 0000000..0ba5ac1
--- /dev/null
@@ -0,0 +1,13 @@
+# Copyright (c) PLUMgrid, Inc.
+# Licensed under the Apache License, Version 2.0 (the "License")
+from distutils.core import setup
+
+setup(name='bpf',
+      version='@REVISION@',
+      description='BPF Loader Library',
+      author='Brenden Blanco',
+      author_email='bblanco@plumgrid.com',
+      url='http://plumgrid.com',
+      packages=['bpf'],
+      platforms=['Linux'],
+      requires=[])
index b08e61b..8fdedd5 100755 (executable)
@@ -20,7 +20,7 @@ S_IP = 4
 
 class TestBPFSocket(TestCase):
     def setUp(self):
-        b = BPF(dp_file=arg1, debug=0)
+        b = BPF(src_file=arg1, debug=0)
         ether_fn = b.load_func("parse_ether", BPF.SCHED_CLS)
         arp_fn = b.load_func("parse_arp", BPF.SCHED_CLS)
         ip_fn = b.load_func("parse_ip", BPF.SCHED_CLS)
index 9601c1f..6175799 100755 (executable)
@@ -8,7 +8,7 @@ name=$1; shift
 kind=$1; shift
 cmd=$1; shift
 
-PYTHONPATH=@CMAKE_SOURCE_DIR@/src
+PYTHONPATH=@CMAKE_SOURCE_DIR@/src/python
 LD_LIBRARY_PATH=@CMAKE_BINARY_DIR@:@CMAKE_BINARY_DIR@/src/cc
 
 ns=$name