From 207754f3e7e0d1e014a60a0b10b3c3c75dabed14 Mon Sep 17 00:00:00 2001 From: David Cournapeau Date: Mon, 26 May 2008 11:29:37 +0000 Subject: Add cpuid + nsis scripts to build win32 installer. --- tools/win32build/README.txt | 9 ++ tools/win32build/cpuid/SConstruct | 5 + tools/win32build/cpuid/cpuid.c | 169 +++++++++++++++++++++ tools/win32build/cpuid/cpuid.h | 20 +++ tools/win32build/cpuid/test.c | 44 ++++++ .../nsis_scripts/numpy-superinstaller-2.4.nsi | 120 +++++++++++++++ .../nsis_scripts/numpy-superinstaller-2.5.nsi | 120 +++++++++++++++ 7 files changed, 487 insertions(+) create mode 100644 tools/win32build/README.txt create mode 100644 tools/win32build/cpuid/SConstruct create mode 100644 tools/win32build/cpuid/cpuid.c create mode 100644 tools/win32build/cpuid/cpuid.h create mode 100644 tools/win32build/cpuid/test.c create mode 100644 tools/win32build/nsis_scripts/numpy-superinstaller-2.4.nsi create mode 100644 tools/win32build/nsis_scripts/numpy-superinstaller-2.5.nsi (limited to 'tools/win32build') diff --git a/tools/win32build/README.txt b/tools/win32build/README.txt new file mode 100644 index 000000000..54989182f --- /dev/null +++ b/tools/win32build/README.txt @@ -0,0 +1,9 @@ +This directory contains various scripts and code to build installers for +windows + - cpuid: contains a mini lib to detect SSE. + - cpucaps: nsis plugin to add the ability to detect SSE for installers. + - *nsi scripts: actual nsis scripts to build the installer + - build.py: script to build various versions of python binaries + (several archs, several python versions) + +To build the binaries, you need blas/lapack/atlas for all architectures. diff --git a/tools/win32build/cpuid/SConstruct b/tools/win32build/cpuid/SConstruct new file mode 100644 index 000000000..3b491deb1 --- /dev/null +++ b/tools/win32build/cpuid/SConstruct @@ -0,0 +1,5 @@ +env = Environment(tools = ['mingw']) + +#libcpuid = env.SharedLibrary('cpuid', source = ['cpuid.c']) +#test = env.Program('test', source = ['test.c'], LIBS = libcpuid, RPATH = ['.']) +test = env.Program('test', source = ['test.c', 'cpuid.c']) diff --git a/tools/win32build/cpuid/cpuid.c b/tools/win32build/cpuid/cpuid.c new file mode 100644 index 000000000..d30d00de8 --- /dev/null +++ b/tools/win32build/cpuid/cpuid.c @@ -0,0 +1,169 @@ +/* + * TODO: + * - test for cpuid availability + * - test for OS support (tricky) + */ + +#include +#include +#include + +#include "cpuid.h" + +#ifndef __GNUC__ +#error "Sorry, this code can only be compiled with gcc for now" +#endif + +/* + * SIMD: SSE 1, 2 and 3, MMX + */ +#define CPUID_FLAG_MMX 1 << 23 /* in edx */ +#define CPUID_FLAG_SSE 1 << 25 /* in edx */ +#define CPUID_FLAG_SSE2 1 << 26 /* in edx */ +#define CPUID_FLAG_SSE3 1 << 0 /* in ecx */ + +/* + * long mode (AMD64 instruction set) + */ +#define CPUID_FLAGS_LONG_MODE 1 << 29 /* in edx */ + +/* + * struct reprensenting the cpuid flags as put in the register + */ +typedef struct { + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; +} cpuid_t; + +/* + * Union to read bytes in 32 (intel) bits registers + */ +union _le_reg { + uint8_t ccnt[4]; + uint32_t reg; +} __attribute__ ((packed)); +typedef union _le_reg le_reg_t ; + +/* + * can_cpuid and read_cpuid are the two only functions using asm + */ +static int can_cpuid(void) +{ + int has_cpuid = 0 ; + + /* + * See intel doc on cpuid (pdf) + */ + asm volatile ( + "pushfl \n\t" + "popl %%eax \n\t" + "movl %%eax, %%ecx \n\t" + "xorl $0x200000, %%eax \n\t" + "pushl %%eax \n\t" + "popfl \n\t" + "pushfl \n\t" + "popl %%eax \n\t" + "xorl %%ecx, %%eax \n\t" + "andl $0x200000, %%eax \n\t" + "movl %%eax,%0 \n\t" + :"=m" (has_cpuid) + : /*no input*/ + : "eax","ecx","cc"); + + return (has_cpuid != 0) ; +} + +/* + * func is the "level" of cpuid. See for cpuid.txt + */ +static cpuid_t read_cpuid(unsigned int func) +{ + cpuid_t res; + + /* we save ebx because it is used when compiled by -fPIC */ + asm volatile( + "pushl %%ebx \n\t" /* save %ebx */ + "cpuid \n\t" + "movl %%ebx, %1 \n\t" /* save what cpuid just put in %ebx */ + "popl %%ebx \n\t" /* restore the old %ebx */ + : "=a"(res.eax), "=r"(res.ebx), + "=c"(res.ecx), "=d"(res.edx) + : "a"(func) + : "cc"); + + return res; +} + +static uint32_t get_max_func() +{ + cpuid_t cpuid; + + cpuid = read_cpuid(0); + return cpuid.eax; +} + +/* + * vendor should have at least CPUID_VENDOR_STRING_LEN characters + */ +static int get_vendor_string(cpuid_t cpuid, char vendor[]) +{ + int i; + le_reg_t treg; + + treg.reg = cpuid.ebx; + for (i = 0; i < 4; ++i) { + vendor[i] = treg.ccnt[i]; + } + + treg.reg = cpuid.edx; + for (i = 0; i < 4; ++i) { + vendor[i+4] = treg.ccnt[i]; + } + + treg.reg = cpuid.ecx; + for (i = 0; i < 4; ++i) { + vendor[i+8] = treg.ccnt[i]; + } + vendor[12] = '\0'; + return 0; +} + +int cpuid_get_caps(cpu_caps_t *cpu) +{ + cpuid_t cpuid; + int max; + + memset(cpu, 0, sizeof(*cpu)); + + if (!can_cpuid()) { + return 0; + } + + max = get_max_func(); + + /* Read vendor string */ + cpuid = read_cpuid(0); + get_vendor_string(cpuid, cpu->vendor); + + if (max < 0x00000001) { + return 0; + } + cpuid = read_cpuid(0x00000001); + + /* We can read mmx, sse 1 2 and 3 when cpuid level >= 0x00000001 */ + if (cpuid.edx & CPUID_FLAG_MMX) { + cpu->has_mmx = 1; + } + if (cpuid.edx & CPUID_FLAG_SSE) { + cpu->has_sse = 1; + } + if (cpuid.edx & CPUID_FLAG_SSE2) { + cpu->has_sse2 = 1; + } + if (cpuid.ecx & CPUID_FLAG_SSE3) { + cpu->has_sse3 = 1; + } + return 0; +} diff --git a/tools/win32build/cpuid/cpuid.h b/tools/win32build/cpuid/cpuid.h new file mode 100644 index 000000000..dc6d2933c --- /dev/null +++ b/tools/win32build/cpuid/cpuid.h @@ -0,0 +1,20 @@ +#ifndef _GABOU_CPUID_H +#define _GABOU_CPUID_H + +#include + +#define CPUID_VENDOR_STRING_LEN 12 + +struct _cpu_caps { + int has_cpuid; + int has_mmx; + int has_sse; + int has_sse2; + int has_sse3; + char vendor[CPUID_VENDOR_STRING_LEN+1]; +}; +typedef struct _cpu_caps cpu_caps_t; + +int cpuid_get_caps(cpu_caps_t *cpuinfo); + +#endif diff --git a/tools/win32build/cpuid/test.c b/tools/win32build/cpuid/test.c new file mode 100644 index 000000000..31f9a7f11 --- /dev/null +++ b/tools/win32build/cpuid/test.c @@ -0,0 +1,44 @@ +#include + +#include "cpuid.h" + +int main() +{ + cpu_caps_t *cpuinfo; + + cpuinfo = malloc(sizeof(*cpuinfo)); + + if (cpuinfo == NULL) { + fprintf(stderr, "Error allocating\n"); + } + + cpuid_get_caps(cpuinfo); + printf("This cpu string is %s\n", cpuinfo->vendor); + + if (cpuinfo->has_mmx) { + printf("This cpu has mmx instruction set\n"); + } else { + printf("This cpu does NOT have mmx instruction set\n"); + } + + if (cpuinfo->has_sse) { + printf("This cpu has sse instruction set\n"); + } else { + printf("This cpu does NOT have sse instruction set\n"); + } + + if (cpuinfo->has_sse2) { + printf("This cpu has sse2 instruction set\n"); + } else { + printf("This cpu does NOT have sse2 instruction set\n"); + } + + if (cpuinfo->has_sse3) { + printf("This cpu has sse3 instruction set\n"); + } else { + printf("This cpu does NOT have sse3 instruction set\n"); + } + + free(cpuinfo); + return 0; +} diff --git a/tools/win32build/nsis_scripts/numpy-superinstaller-2.4.nsi b/tools/win32build/nsis_scripts/numpy-superinstaller-2.4.nsi new file mode 100644 index 000000000..78e5c842e --- /dev/null +++ b/tools/win32build/nsis_scripts/numpy-superinstaller-2.4.nsi @@ -0,0 +1,120 @@ +;-------------------------------- +;Include Modern UI + +!include "MUI2.nsh" + +;SetCompress off ; Useful to disable compression under development + +;-------------------------------- +;General + +;Name and file +Name "Numpy super installer" +OutFile "numpy-1.1.0-win32-superpack-python2.4.exe" + +;Default installation folder +InstallDir "$TEMP" + +;-------------------------------- +;Interface Settings + +!define MUI_ABORTWARNING + +;-------------------------------- +;Pages + +;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt" +;!insertmacro MUI_PAGE_COMPONENTS +;!insertmacro MUI_PAGE_DIRECTORY +;!insertmacro MUI_PAGE_INSTFILES + +;!insertmacro MUI_UNPAGE_CONFIRM +;!insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + +!insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Component Sections + +!include 'Sections.nsh' +!include LogicLib.nsh + +Var HasSSE2 +Var HasSSE3 +Var CPUSSE + +Section "Core" SecCore + + ;SectionIn RO + SetOutPath "$INSTDIR" + + ;Create uninstaller + ;WriteUninstaller "$INSTDIR\Uninstall.exe" + + DetailPrint "Install dir for actual installers is $INSTDIR" + + StrCpy $CPUSSE "0" + CpuCaps::hasSSE2 + Pop $0 + StrCpy $HasSSE2 $0 + + CpuCaps::hasSSE3 + Pop $0 + StrCpy $HasSSE3 $0 + + ; Debug + StrCmp $HasSSE2 "Y" include_sse2 no_include_sse2 + include_sse2: + DetailPrint '"Target CPU handles SSE2"' + StrCpy $CPUSSE "2" + goto done_sse2 + no_include_sse2: + DetailPrint '"Target CPU does NOT handle SSE2"' + goto done_sse2 + done_sse2: + + StrCmp $HasSSE3 "Y" include_sse3 no_include_sse3 + include_sse3: + DetailPrint '"Target CPU handles SSE3"' + StrCpy $CPUSSE "3" + goto done_sse3 + no_include_sse3: + DetailPrint '"Target CPU does NOT handle SSE3"' + goto done_sse3 + done_sse3: + + ClearErrors + + ; Install files conditionaly on detected cpu + ${Switch} $CPUSSE + ${Case} "3" + DetailPrint '"Install SSE 3"' + File "numpy-1.1.0-sse3.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-sse3.exe"' + ${Break} + ${Case} "2" + DetailPrint '"Install SSE 2"' + File "numpy-1.1.0-sse2.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-sse2.exe"' + ${Break} + ${Default} + DetailPrint '"Install NO SSE"' + File "numpy-1.1.0-nosse.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-nosse.exe"' + ${Break} + ${EndSwitch} + + ; Handle errors when executing installers + IfErrors error no_error + + error: + messageBox MB_OK "Executing numpy installer failed" + goto done + no_error: + goto done + done: + +SectionEnd diff --git a/tools/win32build/nsis_scripts/numpy-superinstaller-2.5.nsi b/tools/win32build/nsis_scripts/numpy-superinstaller-2.5.nsi new file mode 100644 index 000000000..f7592b824 --- /dev/null +++ b/tools/win32build/nsis_scripts/numpy-superinstaller-2.5.nsi @@ -0,0 +1,120 @@ +;-------------------------------- +;Include Modern UI + +!include "MUI2.nsh" + +;SetCompress off ; Useful to disable compression under development + +;-------------------------------- +;General + +;Name and file +Name "Numpy super installer" +OutFile "numpy-1.1.0-win32-superpack-python2.5.exe" + +;Default installation folder +InstallDir "$TEMP" + +;-------------------------------- +;Interface Settings + +!define MUI_ABORTWARNING + +;-------------------------------- +;Pages + +;!insertmacro MUI_PAGE_LICENSE "${NSISDIR}\Docs\Modern UI\License.txt" +;!insertmacro MUI_PAGE_COMPONENTS +;!insertmacro MUI_PAGE_DIRECTORY +;!insertmacro MUI_PAGE_INSTFILES + +;!insertmacro MUI_UNPAGE_CONFIRM +;!insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + +!insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Component Sections + +!include 'Sections.nsh' +!include LogicLib.nsh + +Var HasSSE2 +Var HasSSE3 +Var CPUSSE + +Section "Core" SecCore + + ;SectionIn RO + SetOutPath "$INSTDIR" + + ;Create uninstaller + ;WriteUninstaller "$INSTDIR\Uninstall.exe" + + DetailPrint "Install dir for actual installers is $INSTDIR" + + StrCpy $CPUSSE "0" + CpuCaps::hasSSE2 + Pop $0 + StrCpy $HasSSE2 $0 + + CpuCaps::hasSSE3 + Pop $0 + StrCpy $HasSSE3 $0 + + ; Debug + StrCmp $HasSSE2 "Y" include_sse2 no_include_sse2 + include_sse2: + DetailPrint '"Target CPU handles SSE2"' + StrCpy $CPUSSE "2" + goto done_sse2 + no_include_sse2: + DetailPrint '"Target CPU does NOT handle SSE2"' + goto done_sse2 + done_sse2: + + StrCmp $HasSSE3 "Y" include_sse3 no_include_sse3 + include_sse3: + DetailPrint '"Target CPU handles SSE3"' + StrCpy $CPUSSE "3" + goto done_sse3 + no_include_sse3: + DetailPrint '"Target CPU does NOT handle SSE3"' + goto done_sse3 + done_sse3: + + ClearErrors + + ; Install files conditionaly on detected cpu + ${Switch} $CPUSSE + ${Case} "3" + DetailPrint '"Install SSE 3"' + File "numpy-1.1.0-sse3.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-sse3.exe"' + ${Break} + ${Case} "2" + DetailPrint '"Install SSE 2"' + File "numpy-1.1.0-sse2.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-sse2.exe"' + ${Break} + ${Default} + DetailPrint '"Install NO SSE"' + File "numpy-1.1.0-nosse.exe" + ExecWait '"$INSTDIR\numpy-1.1.0-nosse.exe"' + ${Break} + ${EndSwitch} + + ; Handle errors when executing installers + IfErrors error no_error + + error: + messageBox MB_OK "Executing numpy installer failed" + goto done + no_error: + goto done + done: + +SectionEnd -- cgit v1.2.1