Skip to content

Commit

Permalink
Fix missing defines in compilation of cpu_features library
Browse files Browse the repository at this point in the history
  • Loading branch information
althonos committed Jun 19, 2021
1 parent 7acb214 commit 33cd43d
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 83 deletions.
80 changes: 0 additions & 80 deletions pyfastani/_sequtils/sequtils.c

This file was deleted.

86 changes: 86 additions & 0 deletions pyfastani/_sequtils/sequtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include <ctype.h>
#include <stddef.h>

#include "sequtils.h"
#include "complement.h"

#if defined(__x86__) || defined(__x86_64__)
#include "cpuinfo_x86.h"
using namespace cpu_features;
static const X86Features features = GetX86Info().features;
#endif
#ifdef __arm__
#include "cpuinfo_arm.h"
using namespace cpu_features;
static const ArmFeatures features = GetArmInfo().features;
#endif
#ifdef __aarch64__
#include "cpuinfo_aarch64.h"
using namespace cpu_features;
static const Aarch64Features features = GetAarch64Info().features;
#endif

extern "C" {
// --- Fast copy with uppercase --------------------------------------------

void default_copy_upper(char* dst, const char* src, size_t len) {
while (len > 16) {
for (size_t i = 0; i < 16; ++i) {
*dst = toupper(*src);
src++;
dst++;
}
len -= 16;
}
while (len-- > 0) {
*dst = toupper(*src);
src++;
dst++;
}
}

void copy_upper(char* dst, const char* src, size_t len) {
#ifdef __arm__
if (features.neon)
return neon_copy_upper(dst, src, len);
else
#endif
#ifdef __aarch64__
if (features.neon)
return neon_copy_upper(dst, src, len);
else
#endif
#if defined(__x86__) || defined(__x86_64__)
if (features.sse2)
return sse2_copy_upper(dst, src, len); // fast copying plus upper.
else
#endif
return default_copy_upper(dst, src, len);
}


// --- Fast reverse complement ---------------------------------------------

void default_reverse_complement(char* dst, const char* src, size_t len) {
while (len > 16) {
for (size_t i = 0; i < 16; ++i) {
*dst = complement(src[--len]);
dst++;
}
}
while (len > 0) {
*dst = complement(src[--len]);
dst++;
}
}

void reverse_complement(char* dst, const char* src, size_t len) {
#if defined(__x86__) || defined(__x86_64__)
if (features.ssse3)
return ssse3_reverse_complement(dst, src, len); // fast reverse complement.
else
#endif
return default_reverse_complement(dst, src, len);
}

}
77 changes: 74 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@

PLATFORM_MACHINE = platform.machine()
SYS_IMPLEMENTATION = sys.implementation.name
UNIX = not sys.platform.startswith("win")

PROCESSOR_IS_MIPS = PLATFORM_MACHINE.startswith("mips")
PROCESSOR_IS_ARM = PLATFORM_MACHINE.startswith("arm")
PROCESSOR_IS_AARCH64 = PLATFORM_MACHINE.startswith("aarch64")
PROCESSOR_IS_X86 = PLATFORM_MACHINE.startswith(("x86_64", "AMD64", "amd64", "i386", "i486"))
PROCESSOR_IS_POWER = PLATFORM_MACHINE.startswith(("powerpc", "ppc"))


# --- Utils ------------------------------------------------------------------
Expand Down Expand Up @@ -140,6 +147,10 @@ def _silent_spawn(self, cmd):
except subprocess.CalledProcessError as err:
raise CompileError(err.stderr)

def _silent_compile(self, *args, **kwargs):
with mock.patch.object(self.compiler, "spawn", new=self._silent_spawn):
return self.compiler.compile(*args, **kwargs)

# --- Compatibility with base `build_clib` command ---

def check_library_list(self, libraries):
Expand All @@ -153,6 +164,55 @@ def get_source_files(self):

# --- Build code ---

def _has_dlopen(self):
self.mkpath(self.build_temp)
filename = os.path.join(self.build_temp, "test_dlopen.c")
with open(filename, "w") as f:
f.write("""
#include <dlfcn.h>
int main() { dlopen("", 0); }
""")
try:
self.compiler.compile([filename], debug=True)
except CompileError:
log.warn("could not find `dlopen` function from <dlfcn.h>")
return False
else:
log.info("found `dlopen` function from <dlfcn.h>")
return True

def _has_getauxval(self):
self.mkpath(self.build_temp)
filename = os.path.join(self.build_temp, "test_dlopen.c")
with open(filename, "w") as f:
f.write("""
#include <sys/getauxval.h>
int main() { getauxval(0); }
""")
try:
self._silent_compile([filename], debug=True)
except CompileError:
log.warn("could not find `getauxval` function from <sys/getauxval.h>")
return False
else:
log.info("found `getauxval` function from <sys/getauxval.h>")
return True

def _add_platform_defines(self, library):
# add some compatibility defines from `cpu_features`
if PROCESSOR_IS_X86 and sys.platform == "darwin":
library.define_macros.append(("HAVE_SYSCTLBYNAME", 1))
if UNIX:
hardware_detect = False
if self._has_dlopen():
library.define_macros.append(("HAVE_DLFCN_H", 1))
hardware_detect = True
if self._has_getauxval():
library.define_macros.append(("HAVE_STRONG_GETAUXVAL", 1))
hardware_detect = True
if hardware_detect:
library.sources.append(os.path.join("vendor", "cpu_features", "src", "hwcaps.c"))

def build_libraries(self, libraries):
self.mkpath(self.build_clib)
for library in libraries:
Expand All @@ -167,6 +227,10 @@ def build_libraries(self, libraries):
)

def build_library(self, library):
# add specific code for `cpu_features`
if library.name == "cpu_features":
self._add_platform_defines(library)

# update compile flags if compiling in debug or release mode
if self.debug:
if self.compiler.compiler_type in {"unix", "cygwin", "mingw32"}:
Expand All @@ -181,7 +245,7 @@ def build_library(self, library):
for platform_code in library.platform_code:
extra_preargs = library.extra_compile_args + platform_code.extra_compile_args
try:
extra_objects.extend(self.compiler.compile(
extra_objects.extend(self._silent_compile(
platform_code.sources,
output_dir=self.build_temp,
include_dirs=library.include_dirs + [self.build_clib],
Expand All @@ -193,6 +257,7 @@ def build_library(self, library):
except CompileError:
log.warn(f"failed to compile platform-specific {platform_code.platform} code")
else:
log.info(f"successfully built platform-specific {platform_code.platform} code")
self.compiler.define_macro(f"{platform_code.platform}_BUILD_SUPPORTED")

# build objects and create a static library
Expand Down Expand Up @@ -341,6 +406,8 @@ def run(self):

# --- Cython extensions ------------------------------------------------------



libraries = [
Library(
"cpu_features",
Expand All @@ -367,9 +434,13 @@ def run(self):
),
Library(
"sequtils",
include_dirs=[os.path.join("pyfastani", "_sequtils")],
sources=[os.path.join("pyfastani", "_sequtils", "sequtils.c")],
include_dirs=[
os.path.join("pyfastani", "_sequtils"),
os.path.join("vendor", "cpu_features", "include")
],
sources=[os.path.join("pyfastani", "_sequtils", "sequtils.cpp")],
libraries=["cpu_features"],
language="c++",
platform_code=[
PlatformCode(
platform="NEON",
Expand Down

0 comments on commit 33cd43d

Please sign in to comment.