Merge remote-tracking branch 'origin/master' into dvb

This commit is contained in:
Matthias Koefferlein 2019-01-08 00:49:16 +01:00
commit feb2b69aa9
28 changed files with 1359 additions and 332 deletions

View File

@ -1,269 +1,531 @@
matrix:
include:
# python manylinux packages
- name: "cp37-cp37m-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '3.7-dev'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp37-cp37m"
- DOCKER_BUILD=true
- TEST_IN_HOST=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp37-cp37m-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp37-cp37m"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp36-cp36m-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '3.6'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp36-cp36m"
- DOCKER_BUILD=true
- TEST_IN_HOST=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp36-cp36m-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp36-cp36m"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp35-cp35m-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '3.5'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp35-cp35m"
- DOCKER_BUILD=true
- TEST_IN_HOST=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp35-cp35m-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp35-cp35m"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp34-cp34m-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '3.4'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp34-cp34m"
- DOCKER_BUILD=true
- TEST_IN_HOST=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp34-cp34m-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp34-cp34m"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp27-cp27mu-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '2.7'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp27-cp27mu"
- DOCKER_BUILD=true
- TEST_IN_HOST=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp27-cp27mu-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp27-cp27mu"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp27-cp27m-manylinux1_x86_64.whl"
os: linux
sudo: true
language: python
python: '2.7'
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
- PY_VERSION="cp27-cp27m"
- DOCKER_BUILD=true
- TEST_IN_HOST=false # travis's python 2.7 uses ucs4 (mu), so this test fails.
- MATRIX_EVAL=""
cache:
directories:
- ccache
- name: "cp27-cp27m-manylinux1_i686.whl"
os: linux
sudo: true
services:
- docker
env:
- DOCKER_IMAGE="quay.io/pypa/manylinux1_i686"
- PY_VERSION="cp27-cp27m"
- DOCKER_BUILD=true
- MATRIX_EVAL=""
cache:
directories:
- ccache
# python 2 osx
- name: "klayout python2 osx10.13"
# - name: "klayout python2 osx10.13"
- name: "cp27-cp27m-macosx_10_13_x86_64.whl"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL=""
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python2 osx10.12"
# - name: "klayout python2 osx10.12"
- name: "cp27-cp27m-macosx_10_12_x86_64.whl"
os: osx
osx_image: xcode8.3 # macOS 10.12
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL="brew install python2 || brew link --overwrite python@2" # deficient python2 in travis's xcode8.3 (no ssl)
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python2 osx10.11"
# - name: "klayout python2 osx10.11"
- name: "cp27-cp27m-macosx_10_11_x86_64.whl"
os: osx
osx_image: xcode8 # macOS 10.11
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL=""
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
# python 3 osx
- name: "klayout python3 osx10.13"
# - name: "klayout python3 osx10.13"
- name: "cp37-cp37m-macosx_10_13_x86_64.whl"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- python3
- ccache
update: true
env:
- MATRIX_EVAL="shopt -s expand_aliases; alias python='python3'; alias pip='pip3';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=true
- name: "klayout python3.6.6 osx10.13"
# - name: "klayout python3.6.6 osx10.13"
- name: "cp36-cp36m-macosx_10_13_x86_64.whl"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL="brew update; brew install sashkab/python/python36; brew link --force --overwrite python36; shopt -s expand_aliases; alias python='/usr/local/opt/python36/bin/python3.6'; alias pip='/usr/local/opt/python36/bin/pip3.6';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python3.5.6 osx10.13"
# - name: "klayout python3.5.6 osx10.13"
- name: "cp35-cp35m-macosx_10_13_x86_64.whl"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL="brew update; brew install sashkab/python/python35; brew link --force --overwrite python35; shopt -s expand_aliases; alias python='/usr/local/opt/python35/bin/python3.5'; alias pip='/usr/local/opt/python35/bin/pip3.5';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python3.4.9 osx10.13"
# - name: "klayout python3.4.9 osx10.13"
- name: "cp34-cp34m-macosx_10_13_x86_64.whl"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL="brew update; brew install sashkab/python/python34; brew link --force --overwrite python34; shopt -s expand_aliases; alias python='/usr/local/opt/python34/bin/python3.4'; alias pip='/usr/local/opt/python34/bin/pip3.4';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python3 osx10.12"
# - name: "klayout python3 osx10.12"
- name: "cp37-cp37m-macosx_10_12_x86_64.whl"
os: osx
osx_image: xcode8.3 # macOS 10.12
cache: ccache
addons:
homebrew:
packages:
- python3
- ccache
update: true
env:
- MATRIX_EVAL="shopt -s expand_aliases; alias python='python3'; alias pip='pip3';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=true
- name: "klayout python3 osx10.11"
# - name: "klayout python3 osx10.11"
- name: "cp37-cp37m-macosx_10_11_x86_64.whl"
os: osx
osx_image: xcode8 # macOS 10.11
cache: ccache
addons:
homebrew:
packages:
- ccache
env:
- MATRIX_EVAL="brew update; brew config; brew upgrade python; brew postinstall python; ls -l /usr/local/opt/python/libexec/bin/; shopt -s expand_aliases; alias python='/usr/local/opt/python/libexec/bin/python'; alias pip='/usr/local/opt/python/libexec/bin/pip';"
- ARCHFLAGS="-std=c++11"
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- name: "klayout python3.7 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '3.7-dev'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python3.7 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '3.7-dev'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python3.6 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '3.6'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python3.6 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '3.6'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python2.7 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '2.7'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python2.7 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '2.7'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python2.6 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '2.6'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="0" # setuptools installed from last pip has syntax error on py 2.6
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python2.6 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '2.6'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="0" # setuptools installed from last pip has syntax error on py 2.6
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python3.3 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '3.3'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python3.3 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '3.3'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python3.4 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '3.4'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python3.4 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '3.4'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
- name: "klayout python3.5 package"
os: linux
dist: trusty # Ubuntu 14.04
sudo: false
language: python
python: '3.5'
env:
- MATRIX_EVAL=""
- PIP_UPDATE="1"
- PYTHON_BUILD=true
- BREW_BUNDLE=false
- CC=clang
- CXX=clang++
# - name: "klayout python3.5 package"
# os: linux
# dist: trusty # Ubuntu 14.04
# sudo: false
# language: python
# python: '3.5'
# env:
# - MATRIX_EVAL=""
# - PIP_UPDATE="1"
# - PYTHON_BUILD=true
# - CC=clang
# - CXX=clang++
# KLayout builds for mac
# Python 3
- name: "KLayout macOS 10.13 with py3.7"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- python3
- qt
- ccache
update: true
env:
- MATRIX_EVAL=""
- PYTHON_VERSION=B37
- MACOS_VERSION=HighSierra
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
- name: "KLayout macOS 10.12 with py3.7"
os: osx
osx_image: xcode8.3 # macOS 10.12
cache: ccache
addons:
homebrew:
packages:
- python3
- qt
- ccache
update: true
env:
- MATRIX_EVAL=""
- PYTHON_VERSION=B37
- MACOS_VERSION=Sierra
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
- name: "KLayout macOS 10.11 with py3.7"
os: osx
osx_image: xcode8 # macOS 10.11
cache: ccache
addons:
homebrew:
packages:
- python3
update: true
env:
- MATRIX_EVAL=""
- MATRIX_EVAL="brew update; brew config; brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/56c500b569c724b049be7ab9e12d9693f85522f9/Formula/qt.rb" # Qt 5.11.2
- PYTHON_VERSION=B37
- MACOS_VERSION=ElCapitan
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
# Python 2
- name: "KLayout macOS 10.13 with py2.7"
os: osx
osx_image: xcode9.4 # macOS 10.13
cache: ccache
addons:
homebrew:
packages:
- qt
- ccache
update: true
env:
- MATRIX_EVAL=""
- PYTHON_VERSION=Sys
- MACOS_VERSION=HighSierra
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
- name: "KLayout macOS 10.12 with py2.7"
os: osx
osx_image: xcode8.3 # macOS 10.12
cache: ccache
addons:
homebrew:
packages:
- qt
- ccache
update: true
env:
- MATRIX_EVAL=""
- PYTHON_VERSION=Sys
- MACOS_VERSION=Sierra
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
- name: "KLayout macOS 10.11 with py2.7"
os: osx
osx_image: xcode8 # macOS 10.11
cache: ccache
addons:
homebrew:
packages:
- ccache
update: true
env:
- MATRIX_EVAL=""
- MATRIX_EVAL="brew update; brew config; brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/56c500b569c724b049be7ab9e12d9693f85522f9/Formula/qt.rb" # Qt 5.11.2
- PYTHON_VERSION=Sys
- MACOS_VERSION=ElCapitan
- KLAYOUT_BUILD=true
- BREW_BUNDLE=true
before_install:
- env
- gem install dropbox-deployment
- eval "${MATRIX_EVAL}"
- if [ "$BREW_BUNDLE" = true ]; then
find "$(brew --prefix)/Caskroom/"*'/.metadata' -type f -name '*.rb' | xargs grep 'EOS.undent' --files-with-matches | xargs sed -i '' 's/EOS.undent/EOS/';
brew update;
brew bundle;
fi
- if [ "${PIP_UPDATE}" == "1" ]; then
pip --version;
pip install --upgrade pip || sudo pip install --upgrade pip;
@ -271,15 +533,42 @@ before_install:
pip install --upgrade setuptools wheel || sudo pip install --upgrade setuptools wheel;
fi
- python -c "import distutils.sysconfig as sysconfig; print(sysconfig.__file__)"
- if [ "${TRAVIS_OS_NAME}" == "osx" ]; then
export PATH="/usr/local/opt/ccache/libexec:$PATH";
fi
script:
install:
- if [ "$DOCKER_BUILD" = true ]; then
docker pull $DOCKER_IMAGE;
fi
script:
- if [ "$DOCKER_BUILD" = true ]; then
mkdir -p ccache;
mkdir -p wheelhouse;
docker run --rm -e DOCKER_IMAGE -e PY_VERSION -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD "/io/ci-scripts/docker/docker_build.sh";
klayout_version=$(python -c 'import setup; print(setup.Config().version())');
mkdir -p deploy/dist-pymod/$klayout_version;
cp -a wheelhouse/klayout-*manylinux1*.whl deploy/dist-pymod/$klayout_version;
if [ "$TEST_IN_HOST" = true ]; then
pip install klayout --no-index -f ./wheelhouse;
python testdata/pymod/import_db.py;
python testdata/pymod/import_rdb.py;
python testdata/pymod/import_tl.py;
python testdata/pymod/pya_tests.py;
fi
fi
- if [ "$PYTHON_BUILD" = true ]; then
python setup.py build;
python setup.py bdist_wheel;
python setup.py install;
python -m unittest testdata/pymod/import_db.py testdata/pymod/import_rdb.py testdata/pymod/import_tl.py;
mkdir -p deploy/dist-pymod;
cp -a dist/* deploy/dist-pymod/;
python testdata/pymod/import_db.py;
python testdata/pymod/import_rdb.py;
python testdata/pymod/import_tl.py;
python testdata/pymod/pya_tests.py;
klayout_version=$(python -c 'import setup; print(setup.Config().version())');
mkdir -p deploy/dist-pymod/$klayout_version;
cp -a dist/*.whl deploy/dist-pymod/$klayout_version;
python -c 'import klayout.db as db; print(dir(db))';
python -c 'import klayout.rdb as rdb; print(dir(rdb))';
python -c 'import klayout.tl as tl; print(dir(tl))';

View File

@ -1,4 +0,0 @@
tap "homebrew/core"
brew "python3"
brew "python@2", link: false
brew "qt"

152
azure-pipelines.yml Normal file
View File

@ -0,0 +1,152 @@
# https://aka.ms/yaml
jobs:
- job: Build
pool:
vmImage: 'vs2017-win2016' # other options: 'macOS-10.13', 'ubuntu-16.04'
strategy:
matrix:
# Python27:
# python.version: '2.7'
cp35-cp35m-win_amd64.whl:
python.version: '3.5'
python.architecture: 'x64'
cp36-cp36m-win_amd64.whl:
python.version: '3.6'
python.architecture: 'x64'
cp37-cp37m-win_amd64.whl:
python.version: '3.7'
python.architecture: 'x64'
cp35-cp35m-win32.whl:
python.version: '3.5'
python.architecture: 'x86'
cp36-cp36m-win32.whl:
python.version: '3.6'
python.architecture: 'x86'
cp37-cp37m-win32.whl:
python.version: '3.7'
python.architecture: 'x86'
maxParallel: 6
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(python.version)'
architecture: '$(python.architecture)'
# Add additional tasks to run using each Python version in the matrix above
# PowerShell
# Run a PowerShell script on Windows, macOS, or Linux.
- task: PowerShell@2
inputs:
targetType: 'inline' # Optional. Options: filePath, inline
#arguments: # Optional
script: | # Required when targetType == Inline
pwd
Invoke-WebRequest -Uri "https://dl.bintray.com/lightwave-lab/klayout/klayout-microbits-1.0.zip" -OutFile klayout-microbits-1.0.zip
dir
Expand-Archive klayout-microbits-1.0.zip -DestinationPath klayout-microbits
dir klayout-microbits
#errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue
#failOnStderr: false # Optional
#ignoreLASTEXITCODE: false # Optional
#pwsh: false # Optional
#workingDirectory: # Optional
displayName: 'Download and Extract KLayout bits'
# - script: |
# curl https://download.microsoft.com/download/7/9/6/796EF2E4-801B-4FC4-AB28-B59FBF6D907B/VCForPython27.msi -o VCForPython27.msi
# msiexec /i VCForPython27.msi /quiet
# set "VS90COMNTOOLS=C:\Users\VssAdministrator\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC"
# curl https://raw.githubusercontent.com/mattn/gntp-send/master/include/msinttypes/stdint.h -o "%VS90COMNTOOLS%\Include\stdint.h"
# dir "%VS90COMNTOOLS%\Include"
# condition: eq(variables['python.version'], '2.7')
# displayName: 'Install Microsoft Visual C++ Compiler for Python 2.7'
- script: |
python -m pip install --upgrade pip setuptools wheel
displayName: 'Update pip, setuptools and wheel'
- script: |
python -V
set "KLAYOUT_BITS=%cd%\klayout-microbits\klayout-microbits-1.0\msvc2017\%PYTHON_ARCHITECTURE%"
echo KLAYOUT_BITS=%KLAYOUT_BITS%
python setup.py bdist_wheel
displayName: 'Build KLayout'
- bash: |
bash `pwd`/ci-scripts/windows/fix_wheel.sh `pwd`/dist/*.whl "`pwd`/klayout-microbits/klayout-microbits-1.0/msvc2017/$PYTHON_ARCHITECTURE"
displayName: 'Copy klayout bits dlls into wheel'
- script: |
echo PATH=%PATH%
pip install klayout --no-index -f dist
python testdata/pymod/import_db.py
python testdata/pymod/import_rdb.py
python testdata/pymod/import_tl.py
python testdata/pymod/pya_tests.py
displayName: 'Test KLayout pymod'
- task: CopyFiles@2
condition: always()
inputs:
sourceFolder: '$(Build.SourcesDirectory)'
targetFolder: '$(Build.ArtifactStagingDirectory)'
contents: '**/?(*.whl)'
- task: PublishBuildArtifacts@1
condition: always()
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'wheel-$(python.version).$(python.architecture)'
- job: 'Deploy'
displayName: 'Combine Windows wheels'
dependsOn: Build
pool:
vmImage: 'vs2017-win2016' # other options: 'macOS-10.13', 'ubuntu-16.04'
steps:
- checkout: none #skip checking out the default repository resource
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.7.x64'
inputs:
artifactName: 'wheel-3.7.x64'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.6.x64'
inputs:
artifactName: 'wheel-3.6.x64'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.5.x64'
inputs:
artifactName: 'wheel-3.5.x64'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.7.x86'
inputs:
artifactName: 'wheel-3.7.x86'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.6.x86'
inputs:
artifactName: 'wheel-3.6.x86'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: DownloadBuildArtifacts@0
displayName: 'Download Build Artifacts wheel-3.5.x86'
inputs:
artifactName: 'wheel-3.5.x86'
downloadPath: '$(System.DefaultWorkingDirectory)'
- task: CopyFiles@2
condition: always()
inputs:
sourceFolder: '$(System.DefaultWorkingDirectory)'
targetFolder: '$(Build.ArtifactStagingDirectory)'
contents: '**/?(*.whl)'
flattenFolders: true
- task: PublishBuildArtifacts@1
condition: always()
inputs:
pathtoPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'windows_wheels'

View File

@ -0,0 +1,22 @@
Author: Thomas Ferreira de Lima
email: thomas@tlima.me
This folder contains scripts to be run inside docker images. See instructions on how to test this yourself in ci-scripts/docker/development_notes.
## docker_build.sh
We need two environment variables to get going:
```bash
DOCKER_IMAGE="quay.io/pypa/manylinux1_x86_64"
PY_VERSION="cp37-cp37m"
```
The script must be run inside an image pulled from $DOCKER_IMAGE and with klayout's git repo cloned in /io. Inside the git clone folder, run:
```bash
docker run --rm -e DOCKER_IMAGE -e PY_VERSION -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD "/io/ci-scripts/docker/docker_build.sh";
# $PRE_CMD is empty for now (useless currently).
```
This command will generate a wheel and place it in `wheelhouse/klayout-*manylinux1*.whl`. This is the wheel that needs to be uploaded to PyPI via twine. See ci-scripts/twine/README.md.

View File

@ -0,0 +1,17 @@
FROM quay.io/pypa/manylinux1_i686
MAINTAINER Thomas Ferreira de Lima (thomas@tlima.me)
# Install a system package required by our library
RUN linux32 yum install -y zlib-devel
RUN linux32 yum install -y ccache
RUN ln -s /usr/bin/ccache /usr/lib/ccache/c++
RUN ln -s /usr/bin/ccache /usr/lib/ccache/cc
RUN ln -s /usr/bin/ccache /usr/lib/ccache/gcc
RUN ln -s /usr/bin/ccache /usr/lib/ccache/g++
# Add ccache to PATH
RUN mkdir -p /persist/.ccache
ENV CCACHE_DIR="/persist/.ccache"
# Need zip to fix wheel
RUN linux32 yum install -y zip

View File

@ -0,0 +1,17 @@
FROM quay.io/pypa/manylinux1_x86_64
MAINTAINER Thomas Ferreira de Lima (thomas@tlima.me)
# Install a system package required by our library
RUN yum install -y zlib-devel
RUN yum install -y ccache
RUN ln -s /usr/bin/ccache /usr/lib64/ccache/c++
RUN ln -s /usr/bin/ccache /usr/lib64/ccache/cc
RUN ln -s /usr/bin/ccache /usr/lib64/ccache/gcc
RUN ln -s /usr/bin/ccache /usr/lib64/ccache/g++
# Add ccache to PATH
RUN mkdir -p /persist/.ccache
ENV CCACHE_DIR="/persist/.ccache"
# Need zip to fix wheel
RUN yum install -y zip

View File

@ -0,0 +1,221 @@
Author: Thomas Ferreira de Lima
email: thomas@tlima.me
I wrote these notes as I was learning how to use docker and how to build python packages inside a docker image prepared by the pypa team. They require us to build there to allow wheels to have the `manylinux1` tag, meaning that these wheels would be compatible with most linux distributions around. Chapter 1 is about testing in my own computer (MacOS Mojave) and Chapter 2 is about how to automate this build using travis-ci.org.
# Chapter 1. Testing on your own computer
## Step 1.
Make sure you have the quay.io/pypa/manylinux1_x86_64 image.
```bash
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
quay.io/pypa/manylinux1_x86_64 latest 1c8429c548f2 2 months ago 879MB
hello-world latest 4ab4c602aa5e 3 months ago 1.84kB
# My image was old:
$ docker pull quay.io/pypa/manylinux1_x86_64
Using default tag: latest
latest: Pulling from pypa/manylinux1_x86_64
7d0d9526f38a: Already exists
3324bfadf9cb: Pull complete
20f27c7e3062: Pull complete
5bc21fc5fe97: Pull complete
Digest: sha256:a13b2719fb21daebfe25c0173d80f8a85a2326dd994510d7879676e7a2193500
Status: Downloaded newer image for quay.io/pypa/manylinux1_x86_64:latest
```
## Step 2.
This step was inspired by https://dev.to/jibinliu/how-to-persist-data-in-docker-container-2m72
Create a volume for klayout. This is necessary because docker containers don't persist data.
```bash
$ docker volume create klayout-persist
$ docker volume inspect klayout-persist
[
{
"CreatedAt": "2018-12-18T15:01:48Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/klayout-persist/_data",
"Name": "klayout-persist",
"Options": {},
"Scope": "local"
}
]
```
## Step 3.
Build image `myimage` with:
```bash
$ docker build -t myimage:latest -f Dockerfile.x86_64 .
```
This creates an image called `myimage` (temporary). This image will not overwrite old ones. Tip: prune old, unused images with `docker image prune`.
Then I run the docker with a terminal shell and load the volume klayout-persist in /persist:
```bash
$ docker run --name klayout --mount source=klayout-persist,target=/persist -it myimage
```
## Step 4.
In the shell, pull master from klayout.
```bash
cd /persist
git clone https://github.com/lightwave-lab/klayout.git
mkdir -p wheelhouse
cd klayout
# make wheel with python 3.6 (for example)
/opt/python/cp36-cp36m/bin/python setup.py bdist_wheel -d /persist/wheelhouse/
cd /persist
auditwheel repair "wheelhouse/klayout-0.26.0.dev8-cp36-cp36m-linux_x86_64.whl" -w wheelhouse/
# Need to manually fix the wheel
#/opt/python/cp36-cp36m/bin/pip install klayout --no-index -f /wheelhouse
```
The produced wheel from auditwheel, klayout-0.26.0.dev8-cp36-cp36m-manylinux1_x86_64.whl, is defective in the following way: dbcore.so etc. have RPATHs reset to `$ORIGIN/.libs`, so we need to move all .so's `lib_*` into `.libs`, as well as `db_plugins`. We also need to change the dist-info/RECORD file paths. This is a bug from auditwheel, it should either have added a new RPATH, $ORIGIN/.libs, where it places libz, libcurl, libexpat, instead of renaming the existing ones, or moved the files to the right place.
Procedure to fix the wheel:
```bash
unzip wheelhouse/klayout-0.26.0.dev8-cp36-cp36m-manylinux1_x86_64.whl -d tempwheel
cd tempwheel/klayout
mv lib_* db_plugins .libs/
cd ../klayout-0.26.0.dev8.dist-info/
sed -i 's/^klayout\/lib_/klayout\/.libs\/lib_/g' RECORD
sed -i 's/^klayout\/db_plugins/klayout\/.libs\/db_plugins/g' RECORD
cd ../
rm -f ../wheelhouse/klayout-0.26.0.dev8-cp36-cp36m-manylinux1_x86_64.whl
zip -r ../wheelhouse/klayout-0.26.0.dev8-cp36-cp36m-manylinux1_x86_64.whl ./*
cd ..
rm -rf tempwheel
```
Now we can install and test:
```bash
/opt/python/cp36-cp36m/bin/pip install klayout --no-index -f /persist/wheelhouse
cd /persist/klayout
/opt/python/cp36-cp36m/bin/python -m unittest testdata/pymod/import_db.py testdata/pymod/import_rdb.py testdata/pymod/import_tl.py
# Tests passed!
```
Encoded this behavior in a script called fix_wheel.sh. now you only need to run `./fix_wheel.sh wheelhouse/klayout-0.26.0.dev8-cp36-cp36m-manylinux1_x86_64.whl`, and it will overwrite the wheel.
## Step 5. Iterate over all python versions.
For that, we need something like:
```bash
# Compile wheels
for PYBIN in /opt/python/*/bin; do
"${PYBIN}/python" setup.py bdist_wheel -d /persist/wheelhouse/
done
# Bundle external shared libraries into the wheels via auditwheel
for whl in /persist/wheelhouse/*linux_*.whl; do
auditwheel repair "$whl" -w /persist/wheelhouse/
done
# Fix each wheel generated by auditwheel
for whl in /persist/wheelhouse/*manylinux1_*.whl; do
./ci-scripts/docker/fix_wheel.sh "$whl"
done
# Install packages and test
TEST_HOME=/persist/klayout/testdata
for PYBIN in /opt/python/*/bin/; do
"${PYBIN}/pip" install klayout --no-index -f /persist/wheelhouse
"${PYBIN}/python" $TEST_HOME/pymod/import_db.py
"${PYBIN}/python" $TEST_HOME/pymod/import_rdb.py
"${PYBIN}/python" $TEST_HOME/pymod/import_tl.py
```
I tested step 1-5 with both quay.io/pypa/manylinux1_x86_64 and quay.io/pypa/manylinux1_i686. So far the only failure was with `cp27-cp27mu` which gave this import error:
`ImportError: /opt/python/cp27-cp27mu/lib/python2.7/site-packages/klayout/.libs/lib_pya.so: undefined symbol: PyUnicodeUCS2_AsUTF8String`
I noticed that the ccache folder ended up with 800MB. I was hoping that the gcc compilation could reuse a lot of previously built objects but that didn't happen. I think that's because each python comes with its own header. So going forward it doesn't make sense to create a docker image for every python version. I will just cache a ccache folder via travis.
The ccache folder after a single build has 657MB. Go figure.
I discovered that fix_wheel script was actually not properly working. So instead I looked into fixing `auditwheel` directly. Here's the commit that fixes it: https://github.com/thomaslima/auditwheel/tree/87f5306ec02cc68020afaa9933543c898b1d47c1
So now the plan is to change the `docker_build.sh` script so it uses the proper auditwheel, instead of their default.
# Chapter 2. Testing CI flow with docker
# Step 1. Testing commands in own computer
First cloned with:
```bash
git clone git@github.com:lightwave-lab/klayout.git -b tmp/manylinux
cd klayout
```
Let's work with a few environment variables, like in https://github.com/pypa/python-manylinux-demo/blob/master/.travis.yml
DOCKER_IMAGE options: quay.io/pypa/manylinux1_x86_64 quay.io/pypa/manylinux1_i686
PY_VERSION options: cp27-cp27m cp27-cp27mu cp34-cp34m cp35-cp35m cp36-cp36m cp37-cp37m
Total of 2x6 = 12 possibilities
```bash
export DOCKER_IMAGE=quay.io/pypa/manylinux1_x86_64
export PY_VERSION="cp36-cp36m"
docker pull $DOCKER_IMAGE
mkdir -p ccache
mkdir -p wheelhouse
docker run --name klayout -v `pwd` -it $DOCKER_IMAGE
```
Inside docker shell:
```bash
yum install -y zlib-devel
yum install -y zip
yum install -y ccache
ln -s /usr/bin/ccache /usr/lib64/ccache/c++
ln -s /usr/bin/ccache /usr/lib64/ccache/cc
ln -s /usr/bin/ccache /usr/lib64/ccache/gcc
ln -s /usr/bin/ccache /usr/lib64/ccache/g++
echo $PATH
# /usr/lib64/ccache:/opt/rh/devtoolset-2/root/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
export CCACHE_DIR="/io/ccache"
# Compile wheel
/opt/python/$PY_VERSION/bin/python setup.py bdist_wheel -d /io/wheelhouse/
# Bundle external shared libraries into the wheels via auditwheel
for whl in /io/wheelhouse/*linux_*.whl; do
auditwheel repair "$whl" -w /io/wheelhouse/
done
# Fix each wheel generated by auditwheel
for whl in /io/wheelhouse/*manylinux1_*.whl; do
./ci-scripts/docker/fix_wheel.sh "$whl"
done
```
# Step 2. Automating step 1 in travis (CI).
DOCKER_IMAGE options: quay.io/pypa/manylinux1_x86_64 quay.io/pypa/manylinux1_i686
PY_VERSION options: cp27-cp27m cp27-cp27mu cp34-cp34m cp35-cp35m cp36-cp36m cp37-cp37m
Build: spawn 12 travis jobs, one for each combination of word-size and python version.
Output: populated ./ccache with compiled objects and wheels inside ./wheelhouse/, one useless, `*linux_*.whl` and one useful `*manylinux1_*.whl`.
Post-build:
- cache `./ccache`
- deploy `./wheelhouse/*manylinux1_*.whl` to dropbox (./deploy folder)
# Step 3. Automating deployment to PyPI:
TBD

View File

@ -0,0 +1,77 @@
#!/usr/bin/env bash
SCRIPT_NAME=`basename "$0"`
TMP_WHEEL="/tmp/klayout_tempwheel"
display_usage() {
echo "This script fixes auditwheel-repaired wheels."
echo "Caution: This will delete the original wheel."
echo -e "\nUsage:\n./${SCRIPT_NAME} [--help|-h] klayout-...-manylinux1_x86_64.whl \n"
}
if [[ ( $1 == "--help") || $1 == "-h" ]]
then
display_usage
exit 0
fi
# Check number of arguments
if [ $# -eq 0 ]; then
>&2 echo -e "ERROR: No filename supplied\n"
display_usage
exit 1
elif [ ! $# -eq 1 ]; then
>&2 echo -e "ERROR: Too many files supplied. Provide one filename at at time.\n"
display_usage
exit 1
fi
# Read wheel file from argument
WHL="$1"
# Check WHL is a valid file
if [[ ! -f "$WHL" ]]; then
>&2 echo -e "ERROR: $WHL is not a file"
exit 1
fi
# Convert to absolute path (linux only)
WHL=$(readlink -f $WHL)
# Record old current directory
OLD_PWD=$PWD
# The produced wheel from auditwheel, klayout-*-manylinux1_x86_64.whl, is defective in the following way: dbcore.so etc. have RPATHs reset to `$ORIGIN/.libs`, so we need to move all .so's `lib_*` into `.libs`, as well as `db_plugins`. We also need to change the dist-info/RECORD file paths. This is a bug from auditwheel, it should either have added a new RPATH, $ORIGIN/.libs, where it places libz, libcurl, libexpat, instead of renaming the existing ones, or moved the files to the right place.
# Checking if it was previously patched
if unzip -l $WHL | grep -q 'patched_after_auditwheel_repair'; then
echo "$(basename $WHL) is already patched. Doing nothing."
exit 0
fi
# Repair script below
if [[ -d $TMP_WHEEL ]]; then
rm -rf $TMP_WHEEL
fi
echo "Unpacking $WHL into $TMP_WHEEL"
unzip -q $WHL -d $TMP_WHEEL
cd $TMP_WHEEL/klayout
echo "Moving files: mv lib_* db_plugins .libs/"
mv lib_* db_plugins .libs/ 2>/dev/null
if [ $? -ne 0 ]; then
>&2 echo "ERROR: lib_*.so or db_plubins not found. Quitting."
exit 1
fi
cd ../klayout-*.dist-info/
echo "Patching klayout-*.dist-info/RECORD"
sed -i 's/^klayout\/lib_/klayout\/.libs\/lib_/g' RECORD
sed -i 's/^klayout\/db_plugins/klayout\/.libs\/db_plugins/g' RECORD
cd ../
touch $TMP_WHEEL/patched_after_auditwheel_repair
echo "Packing $WHL from $TMP_WHEEL"
rm -f $WHL
zip -rq $WHL ./*
echo "Done. $(basename $WHL) is patched."
# Cleanup (should always execute)
cd $OLD_PWD

View File

@ -0,0 +1,38 @@
#!/bin/bash
# run with docker run --rm -v `pwd`:/io $DOCKER_IMAGE $PRE_CMD /io/ci-scripts/manylinux-docker.sh
# see https://github.com/pypa/python-manylinux-demo/blob/master/.travis.yml
# cache using https://github.com/travis-ci/travis-ci/issues/5358
set -e -x
# Install a system package required by our library
yum install -y zlib-devel
yum install -y ccache
ln -s /usr/bin/ccache /usr/lib64/ccache/c++
ln -s /usr/bin/ccache /usr/lib64/ccache/cc
ln -s /usr/bin/ccache /usr/lib64/ccache/gcc
ln -s /usr/bin/ccache /usr/lib64/ccache/g++
# export PATH=/usr/lib64/ccache:$PATH # unnecessary
# Compile wheels
for PYBIN in /opt/python/*/bin; do
"${PYBIN}/python" setup.py bdist_wheel -d /persist/wheelhouse/
done
# Bundle external shared libraries into the wheels via auditwheel
for whl in /persist/wheelhouse/*linux_*.whl; do
auditwheel repair "$whl" -w /persist/wheelhouse/
done
# Fix each wheel generated by auditwheel
for whl in /persist/wheelhouse/*manylinux1_*.whl; do
./ci-scripts/docker/fix_wheel.sh "$whl"
done
# Install packages and test
TEST_HOME=/persist/klayout/testdata
for PYBIN in /opt/python/*/bin/; do
"${PYBIN}/pip" install klayout --no-index -f /persist/wheelhouse
"${PYBIN}/python" $TEST_HOME/pymod/import_db.py
"${PYBIN}/python" $TEST_HOME/pymod/import_rdb.py
"${PYBIN}/python" $TEST_HOME/pymod/import_tl.py
done

View File

@ -0,0 +1,73 @@
#!/usr/bin/env bash
if [[ -z $PY_VERSION ]]; then
echo '$PY_VERSION is not set'
exit 1
fi
if [[ -z $DOCKER_IMAGE ]]; then
echo '$DOCKER_IMAGE is not set'
exit 1
fi
echo PY_VERSION=$PY_VERSION
echo DOCKER_IMAGE=$DOCKER_IMAGE
# sometimes the epel server is down. retry 5 times
for i in $(seq 1 5); do
yum install -y zlib-devel ccache zip git && s=0 && break || s=$? && sleep 15;
done
[ $s -eq 0 ] || exit $s
if [[ $DOCKER_IMAGE == "quay.io/pypa/manylinux1_x86_64" ]]; then
ln -s /usr/bin/ccache /usr/lib64/ccache/c++
ln -s /usr/bin/ccache /usr/lib64/ccache/cc
ln -s /usr/bin/ccache /usr/lib64/ccache/gcc
ln -s /usr/bin/ccache /usr/lib64/ccache/g++
export PATH="/usr/lib64/ccache/:$PATH"
elif [[ $DOCKER_IMAGE == "quay.io/pypa/manylinux1_i686" ]]; then
ln -s /usr/bin/ccache /usr/lib/ccache/c++
ln -s /usr/bin/ccache /usr/lib/ccache/cc
ln -s /usr/bin/ccache /usr/lib/ccache/gcc
ln -s /usr/bin/ccache /usr/lib/ccache/g++
export PATH="/usr/lib/ccache/:$PATH"
fi
echo $PATH
export CCACHE_DIR="/io/ccache"
# Download proper auditwheel program
git clone https://github.com/thomaslima/auditwheel.git /tmp/auditwheel
cd /tmp/auditwheel
git checkout 87f5306ec02cc68020afaa9933543c898b1d47c1 # patched version
AUDITWHEEL_PYTHON=$(cat `which auditwheel` | head -1 | sed -e 's/#!\(.*\)/\1/')
# Install auditwheel, replacing the system's auditwheel binary
$AUDITWHEEL_PYTHON -m pip install .
# Show ccache stats
echo "Cache stats:"
ccache -s
# Compile wheel
cd /io
"/opt/python/$PY_VERSION/bin/python" setup.py bdist_wheel -d /io/wheelhouse/ || exit 1
# Show ccache stats
echo "Cache stats:"
ccache -s
# Bundle external shared libraries into the wheels via auditwheel
for whl in /io/wheelhouse/*linux_*.whl; do
auditwheel -v repair "$whl" -w /io/wheelhouse/ || exit 1
done
# Install packages and test
TEST_HOME=/io/testdata
"/opt/python/$PY_VERSION/bin/pip" install klayout --no-index -f /io/wheelhouse || exit 1
"/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_db.py || exit 1
"/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_rdb.py || exit 1
"/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/import_tl.py || exit 1
"/opt/python/$PY_VERSION/bin/python" $TEST_HOME/pymod/pya_tests.py || exit 1

View File

@ -0,0 +1,15 @@
After building all the travis wheels, go to the folder where the wheels were deployed. In my case, for example, `/Users/tlima/Dropbox/Apps/travis-deploy/Builds/klayout/dist-pymod/0.26.0.dev10`.
Then, run the command
```bash
travis upload *.whl
```
, which will ask for an username and password related to your account.
After this upload was successful, you can upload the source tarball. Go to klayout's git folder and run `python setup.py sdist`. Inside `dist/`, you'll find a tarball named, e.g., `klayout-0.26.0.dev10.tar.gz`. So just run
```bash
travis upload klayout-0.26.0.dev10.tar.gz
```

View File

@ -0,0 +1,84 @@
#!/usr/bin/env bash
SCRIPT_NAME=`basename "$0"`
TMP_WHEEL="$PWD/tmp/klayout_tempwheel"
display_usage() {
echo "This script includes external libraries in windows-based wheels."
echo "Caution: This will delete the original wheel."
echo -e "\nUsage:\n./${SCRIPT_NAME} [--help|-h] klayout-...-win_amd64.whl \n"
}
if [[ ( $1 == "--help") || $1 == "-h" ]]
then
display_usage
exit 0
fi
# Check number of arguments
if [ $# -eq 0 ]; then
>&2 echo -e "ERROR: No filename supplied\n"
display_usage
exit 1
elif [ ! $# -eq 2 ]; then
>&2 echo -e "ERROR: Too many files supplied. Provide one filename at at time.\n"
display_usage
exit 1
fi
# Read wheel file from argument
WHL="$1"
WHL=$(echo $WHL | sed 's/\\/\//g' | sed 's/://')
KLAYOUT_BITS="$2"
KLAYOUT_BITS=$(echo $KLAYOUT_BITS | sed 's/\\/\//g' | sed 's/://')
# Check WHL is a valid file
if [[ ! -f "$WHL" ]]; then
>&2 echo -e "ERROR: $WHL is not a file"
exit 1
fi
# Convert to absolute path (linux only)
WHL=$(readlink -f $WHL)
# Record old current directory
OLD_PWD=$PWD
# Need to include external DLLs (klayout bits) into wheel
# # Checking if it was previously patched
# if unzip -l $WHL | grep -q 'patch_external_libraries_included'; then
# echo "$(basename $WHL) is already patched. Doing nothing."
# exit 0
# fi
# Repair script below
if [[ -d $TMP_WHEEL ]]; then
rm -rf $TMP_WHEEL
else
mkdir -p $TMP_WHEEL
fi
echo "Unpacking $WHL inside $TMP_WHEEL"
wheel unpack $WHL -d $TMP_WHEEL || exit 1
TMP_WHEEL="$TMP_WHEEL/`ls $TMP_WHEEL`"
cd $TMP_WHEEL/klayout
echo "Copying libraries: libcurl.dll, expat.dll, pthreadVCE2.dll, zlib1.dll"
echo pwd: `pwd`
cp -v $KLAYOUT_BITS/curl/bin/* .
cp -v $KLAYOUT_BITS/expat/bin/* .
cp -v $KLAYOUT_BITS/ptw/bin/* .
cp -v $KLAYOUT_BITS/zlib/bin/* .
# if [ $? -ne 0 ]; then
# >&2 echo "ERROR: lib not found. Quitting."
# exit 1
# fi
cd $TMP_WHEEL
# touch $TMP_WHEEL/patch_external_libraries_included
echo "Packing $WHL from $TMP_WHEEL"
rm -f $WHL
wheel pack $TMP_WHEEL -d `dirname $WHL` || exit 1
echo "Done. $(basename $WHL) is patched."
# Cleanup (should always execute)
cd $OLD_PWD

View File

@ -59,13 +59,13 @@ from setuptools.extension import Extension, Library
import glob
import os
import platform
import distutils.sysconfig as sysconfig
from distutils.errors import CompileError
import distutils.command.build_ext
import setuptools.command.build_ext
import multiprocessing
N_cores = multiprocessing.cpu_count()
# monkey-patch for parallel compilation
# from https://stackoverflow.com/questions/11013851/speeding-up-build-process-with-distutils
def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None):
@ -88,6 +88,7 @@ def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=N
n_tries = 2
while n_tries > 0:
try:
print("Building", obj)
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
except CompileError:
n_tries -= 1
@ -95,7 +96,7 @@ def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=N
else:
break
# convert to list, imap is evaluated on-demand
list(multiprocessing.pool.ThreadPool(N).imap(_single_compile, objects))
list(multiprocessing.pool.ThreadPool(N).map(_single_compile, objects))
return objects
@ -155,10 +156,10 @@ distutils.ccompiler.CCompiler.library_filename = patched_library_filename
# for this ... We're patching this back now.
def always_link_shared_object(
self, objects, output_libname, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
self, objects, output_libname, output_dir=None, libraries=None,
library_dirs=None, runtime_library_dirs=None, export_symbols=None,
debug=0, extra_preargs=None, extra_postargs=None, build_temp=None,
target_lang=None):
self.link(
self.SHARED_LIBRARY, objects, output_libname,
output_dir, libraries, library_dirs, runtime_library_dirs,
@ -166,6 +167,7 @@ def always_link_shared_object(
build_temp, target_lang
)
setuptools.command.build_ext.libtype = "shared"
setuptools.command.build_ext.link_shared_object = always_link_shared_object
@ -320,7 +322,7 @@ class Config(object):
"""
Gets the version string
"""
return "0.26.0.dev8"
return "0.26.0.dev11"
config = Config()
@ -496,6 +498,17 @@ if __name__ == '__main__':
long_description='TODO',
author='Matthias Koefferlein',
author_email='matthias@klayout.de',
classifiers=[
# Recommended classifiers
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 3",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: MacOS :: MacOS X",
"Operating System :: Microsoft :: Windows",
"Operating System :: POSIX :: Linux",
# Optional classifiers
"Topic :: Scientific/Engineering :: Electronic Design Automation (EDA)",
],
url='https://github.com/klayoutmatthias/klayout',
packages=find_packages('src/pymod/distutils_src'),
package_dir={'': 'src/pymod/distutils_src'}, # https://github.com/pypa/setuptools/issues/230

View File

@ -256,7 +256,7 @@ gsi::Class<db::Technology> technology_decl ("db", "Technology",
gsi::method ("load", &db::Technology::load, gsi::arg ("file"),
"@brief Loads the technology definition from a file\n"
) +
gsi::method ("load", &db::Technology::save, gsi::arg ("file"),
gsi::method ("save", &db::Technology::save, gsi::arg ("file"),
"@brief Saves the technology definition to a file\n"
) +
gsi::method ("technology_names", &technology_names,

View File

@ -83,7 +83,7 @@ A &A::operator= (const A &a)
return *this;
}
int A::a0 ()
int A::instance_count ()
{
return a_count;
}
@ -780,6 +780,7 @@ static gsi::QFlagsClass<Enum> decl_qflags_enum ("", "Enums");
static gsi::Class<A> decl_a ("", "A",
gsi::constructor ("new_a|new", &a_ctor) +
gsi::method ("instance_count", &A::instance_count) +
gsi::method ("br", &A::br) +
gsi::method ("get_e", &A::get_e) +
gsi::method ("get_eptr", &A::get_eptr) +
@ -814,7 +815,6 @@ static gsi::Class<A> decl_a ("", "A",
gsi::method ("af?|af", &A::af1) +
gsi::method ("aa", &A::a) +
gsi::method ("aa", &A::a_static) +
gsi::method ("a0", &A::a0) +
gsi::method ("a1", &A::a1) +
gsi::method ("a1c", &A::a1c) +
gsi::method ("a2", &A::a2) +
@ -904,22 +904,22 @@ static gsi::Class<B> decl_b ("", "B",
gsi::method ("b5", &B::b5) +
gsi::method ("b5a", &B::b5a) +
gsi::method ("b5b", &B::b5b) +
gsi::method ("b6|make_a", &B::b6) +
gsi::method ("b8|set_an", &B::b8) +
gsi::method ("b9|an", &B::b9) +
gsi::method ("b8cref|set_an_cref", &B::b8) +
gsi::method ("b9cref|an_cref", &B::b9) +
gsi::method ("make_a", &B::make_a) +
gsi::method ("set_an", &B::set_an) +
gsi::method ("an", &B::an) +
gsi::method ("set_an_cref", &B::set_an_cref) +
gsi::method ("an_cref", &B::an_cref) +
// implemented by extension below:
// gsi::iterator_ext ("b10", &b10b_ext, &b10e_ext) +
gsi::iterator ("b10_nc", &B::b10b_nc, &B::b10e_nc) +
gsi::iterator ("b11", &B::b11b, &B::b11e) +
gsi::iterator ("b12", &B::b12b, &B::b12e) +
gsi::iterator ("b13", &B::b13b, &B::b13e) +
gsi::method ("b14a|amember_or_nil", &B::amember_or_nil) +
gsi::method ("b14b|amember_ptr", &B::amember_ptr) +
gsi::method ("b7|b14c|amember_cptr", &B::amember_cptr) +
gsi::method ("b7c|amember_cref", &B::amember_cref) +
gsi::method ("b7d|amember_ref", &B::amember_ref) +
gsi::method ("amember_or_nil_alt|amember_or_nil", &B::amember_or_nil) +
gsi::method ("amember_ptr_alt|amember_ptr", &B::amember_ptr) +
gsi::method ("xxx|amember_cptr", &B::amember_cptr) +
gsi::method ("yyy|amember_cref", &B::amember_cref) +
gsi::method ("zzz|amember_ref", &B::amember_ref) +
gsi::method ("b15|arg_is_not_nil", &B::b15) +
gsi::method ("b16a|av", &B::b16a) +
gsi::method ("b16b|av_cref", &B::b16b) +

View File

@ -104,7 +104,7 @@ struct A
void set_af (bool _f) { f = _f; }
bool af1 (bool /*dummy*/) { return f; }
static int a0 ();
static int instance_count ();
int a1 () {
return n;
}
@ -465,26 +465,26 @@ struct B
return m.c_str ();
}
A b6 (int n) {
A make_a (int n) {
return A(n);
}
void b8 (int n)
void set_an (int n)
{
a.n = n;
}
int b9 (A a)
int an (A a)
{
return a.n;
}
void b8cref (const int &n)
void set_an_cref (const int &n)
{
a.n = n;
}
const int &b9cref (const A &a)
const int &an_cref (const A &a)
{
return a.n;
}

View File

@ -38,14 +38,14 @@ TEST(1)
tl::Eval e;
tl::Variant v;
v = e.parse ("A.a0").execute ();
v = e.parse ("A.instance_count").execute ();
int base_insts = v.to_int ();
EXPECT_EQ (base_insts, 0);
v = e.parse ("A.new(35).to_s").execute ();
EXPECT_EQ (v.to_string (), std::string ("A: 35"));
EXPECT_EQ (e.parse ("A.a0").execute ().to_int (), 0);
EXPECT_EQ (e.parse ("A.instance_count").execute ().to_int (), 0);
// mapping of to_string to to_s method
v = e.parse ("A.new(35)").execute ();
@ -97,11 +97,11 @@ TEST(1)
EXPECT_EQ (v.to_string (), std::string ("0.125"));
v = e.parse ("a.a4([5, 1, -1.25])").execute ();
EXPECT_EQ (v.to_string (), std::string ("-1.25"));
v = e.parse ("A.a0").execute ();
v = e.parse ("A.instance_count").execute ();
EXPECT_EQ (v.to_int (), base_insts + 1); // one instance more
v = e.parse ("a=1; A.a0").execute ();
v = e.parse ("a=1; A.instance_count").execute ();
EXPECT_EQ (v.to_int (), base_insts); // remaining instances
v = e.parse ("A.a0").execute ();
v = e.parse ("A.instance_count").execute ();
EXPECT_EQ (v.to_int (), base_insts); // remaining instances
v = e.parse ("var a1=A.new; a1.a5(-15); var a2=a1.dup; a2.a5(107); a1.a1").execute ();

View File

@ -176,7 +176,7 @@
&lt;version&gt;Version&lt;/version&gt;
&lt;title&gt;Title of the package&lt;/title&gt;
&lt;doc&gt;A brief description&lt;/doc&gt;
&lt;doc_url&gt;Documentation URL&lt;/doc_url&gt;
&lt;doc-url&gt;Documentation URL&lt;/doc-url&gt;
&lt;url&gt;Download URL&lt;/url&gt;
&lt;license&gt;License model&lt;/license&gt;
&lt;icon&gt;Icon image: base64-encoded, 64x64 max, PNG preferred&lt;/icon&gt;

View File

@ -450,7 +450,7 @@ void install_signal_handlers ()
act.sa_sigaction = signal_handler;
sigemptyset (&act.sa_mask);
act.sa_flags = SA_SIGINFO;
#if !defined(__APPLE__)
#if !defined(__APPLE__) && !defined(__OpenBSD__)
act.sa_restorer = 0;
#endif

View File

@ -33,17 +33,14 @@
<number>9</number>
</property>
<item>
<widget class="QFrame" name="frame_2">
<widget class="QFrame" name="tech_frame">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
@ -56,17 +53,17 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_2">
<item row="0" column="1">
<widget class="QComboBox" name="tech_cbx"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="tech_cbx_label">
<property name="text">
<string>Technology to be associated with layout</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="tech_cbx"/>
</item>
<item>
<item row="0" column="2">
<spacer>
<property name="orientation">
<enum>Qt::Horizontal</enum>
@ -79,25 +76,25 @@
</property>
</spacer>
</item>
<item row="1" column="0" colspan="3">
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>10</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QFrame" name="frame">
<property name="frameShape">

View File

@ -187,7 +187,7 @@ LoadLayoutOptionsDialog::update ()
}
const db::Technology *tech = m_tech_array [m_technology_index];
mp_ui->options_tab->setEnabled (tech && tech->is_persisted ());
mp_ui->options_tab->setEnabled (!tech || tech->is_persisted ());
for (std::vector< std::pair<StreamReaderOptionsPage *, std::string> >::iterator page = m_pages.begin (); page != m_pages.end (); ++page) {
if (page->first) {
@ -240,6 +240,7 @@ LoadLayoutOptionsDialog::edit_global_options (lay::PluginRoot *config_root, db::
mp_ui->tech_cbx->blockSignals (false);
mp_ui->tech_cbx->show ();
mp_ui->tech_frame->show ();
if (get_options_internal ()) {
@ -271,7 +272,7 @@ LoadLayoutOptionsDialog::edit_global_options (lay::PluginRoot *config_root, db::
bool
LoadLayoutOptionsDialog::get_options (db::LoadLayoutOptions &options)
{
mp_ui->tech_cbx->hide ();
mp_ui->tech_frame->hide ();
mp_ui->always_cbx->hide ();
m_opt_array.clear ();

View File

@ -154,11 +154,11 @@ BasicText::produce (const db::Layout &layout, const std::vector<unsigned int> &l
const db::TextGenerator &font = db::TextGenerator::generators ()[f];
double m = parameters [p_magnification].to_double ();
db::Coord b = parameters [p_bias].to_double ();
double b = parameters [p_bias].to_double ();
bool inv = parameters [p_inverse].to_bool ();
db::Coord dx = parameters [p_char_spacing].to_double ();
db::Coord dy = parameters [p_line_spacing].to_double ();
double dx = parameters [p_char_spacing].to_double ();
double dy = parameters [p_line_spacing].to_double ();
std::string t = parameters [p_text].to_string ();

View File

@ -538,7 +538,7 @@ PYAObjectBase::destroy ()
return;
}
if (!m_can_destroy && m_obj) {
if (! (m_owned || m_can_destroy) && m_obj) {
throw tl::Exception (tl::to_string (tr ("Object cannot be destroyed explicitly")));
}

View File

@ -1,5 +1,4 @@
# klayout library definition file
__all__ = [ "tl", "db", "lay", "rdb" ]
__all__ = [ "tl", "db", "rdb" ]

View File

@ -1,10 +1,7 @@
# import all packages from klayout, such as klayout.db and klayout.tl
# WARNING: doing it manually until it becomes impractical
# TODO: We need a specification document explaining what should go into pya
import klayout
import importlib
__all__ = []
for m in klayout.__all__:
mod = importlib.import_module("klayout." + m)
for mm in mod.__all__:
globals()[mm] = getattr(mod, mm)
from klayout.db import * # noqa
from klayout.tl import * # noqa
from klayout.rdb import * # noqa

View File

@ -364,7 +364,7 @@ Proxy::destroy ()
return;
}
if (!m_can_destroy && m_obj) {
if (! (m_owned || m_can_destroy) && m_obj) {
throw tl::Exception (tl::to_string (tr ("Object cannot be destroyed explicitly")));
}

View File

@ -135,10 +135,10 @@ class BasicTest(unittest.TestCase):
def test_00(self):
# all references of PA are released now:
ac0 = pya.A.a0()
ic0 = pya.A.instance_count()
a = pya.A.new_a(100)
self.assertEqual( pya.A.a0(), ac0 + 1 )
self.assertEqual( pya.A.instance_count(), ic0 + 1 )
a = pya.A()
self.assertEqual(a.a1(), 17)
@ -146,28 +146,28 @@ class BasicTest(unittest.TestCase):
self.assertEqual(a.a1(), 110)
a = None
self.assertEqual( pya.A.a0(), ac0 )
self.assertEqual( pya.A.instance_count(), ic0 )
a = pya.A()
self.assertEqual( pya.A.a0(), ac0 ) # delayed instantiation of detached objects - A is actually created if it is used first
self.assertEqual( pya.A.instance_count(), ic0 ) # delayed instantiation of detached objects - A is actually created if it is used first
a.a2() # just check, if it can be called
self.assertEqual( pya.A.a0(), ac0 + 1 )
self.assertEqual( pya.A.instance_count(), ic0 + 1 )
# open question: with ruby 1.8, aa is not deleted if the self.assertEqual is missing. Why?
# maybe the GC does not like to be called that frequently?
aa = a.dup()
self.assertEqual( pya.A.a0(), ac0 + 2 )
self.assertEqual( pya.A.instance_count(), ic0 + 2 )
aa = None
self.assertEqual( pya.A.a0(), ac0 + 1 )
self.assertEqual( pya.A.instance_count(), ic0 + 1 )
a = None
self.assertEqual( pya.A.a0(), ac0 )
self.assertEqual( pya.A.instance_count(), ic0 )
a = pya.A()
self.assertEqual( pya.A.a0(), ac0 ) # delayed instantiation of detached objects - A is actually created if it is used first
self.assertEqual( pya.A.instance_count(), ic0 ) # delayed instantiation of detached objects - A is actually created if it is used first
a.a2() # just check, if it can be called
self.assertEqual( pya.A.a0(), ac0 + 1 )
self.assertEqual( pya.A.instance_count(), ic0 + 1 )
# static and non-static methods can be mixed, but they will be made non-ambiguous too
self.assertEqual( pya.A.aa(), "static_a" )
@ -219,7 +219,7 @@ class BasicTest(unittest.TestCase):
self.assertEqual(arr, [5, 1, -1.25])
a.destroy()
self.assertEqual( pya.A.a0(), ac0 )
self.assertEqual( pya.A.instance_count(), ic0 )
if not leak_check:
@ -237,13 +237,13 @@ class BasicTest(unittest.TestCase):
error_caught = True
self.assertEqual( error_caught, True )
self.assertEqual( pya.A.a0(), ac0 )
self.assertEqual( pya.A.instance_count(), ic0 )
a = pya.A.new_a( 55 )
self.assertEqual( pya.A.a0(), ac0 + 1 )
self.assertEqual( pya.A.instance_count(), ic0 + 1 )
self.assertEqual( a.a1(), 55 )
self.assertEqual( a.a_vp1( a.a_vp2() ), "abc" )
a.destroy()
self.assertEqual( pya.A.a0(), ac0 )
self.assertEqual( pya.A.instance_count(), ic0 )
a = pya.A.new_a(0)
self.assertEqual( str(a.a9a(5)), "True" )
@ -594,12 +594,12 @@ class BasicTest(unittest.TestCase):
err_caught = False
try:
b.b7().a1() # cannot call non-const method on const reference
b.amember_cptr().a1() # cannot call non-const method on const reference
except:
err_caught = True
self.assertEqual( err_caught, True )
b.b7().a2()
b.amember_cptr().a2()
self.assertEqual( b.b1(), 5 )
self.assertEqual( b.b2(), "" )
@ -973,50 +973,58 @@ class BasicTest(unittest.TestCase):
# test copies of objects being returned
b = pya.B()
b._create() # force constructor of B to allocate some A instances internally
a = b.b6( 1971 );
a_count = pya.A.instance_count()
a = b.make_a( 1971 );
self.assertEqual( pya.A.instance_count(), a_count + 1 )
self.assertEqual( a.a1(), 1971 );
self.assertEqual( b.b9( a ), 1971 );
self.assertEqual( b.an( a ), 1971 );
aa = b.b6( -61 );
self.assertEqual( b.b9cref( aa ), -61 );
aa = b.make_a( -61 );
self.assertEqual( pya.A.instance_count(), a_count + 2 )
self.assertEqual( b.an_cref( aa ), -61 );
self.assertEqual( a.a1(), 1971 );
self.assertEqual( b.b9( a ), 1971 );
self.assertEqual( b.an( a ), 1971 );
self.assertEqual( aa.a1(), -61 );
self.assertEqual( b.b9( aa ), -61 );
self.assertEqual( b.an( aa ), -61 );
aa.a5(98);
a.a5(100);
self.assertEqual( a.a1(), 100 );
self.assertEqual( b.b9( a ), 100 );
self.assertEqual( b.an( a ), 100 );
self.assertEqual( aa.a1(), 98 );
self.assertEqual( b.b9( aa ), 98 );
self.assertEqual( b.an( aa ), 98 );
a._destroy()
aa = None
self.assertEqual( pya.A.instance_count(), a_count )
def test_18(self):
# Test references to objects (returned by b.b7)
# Test references to objects (returned by b.amember_cptr)
b = pya.B()
b.b8( 77 )
self.assertEqual( b.b7().a1c(), 77 );
b.set_an( 77 )
self.assertEqual( b.amember_cptr().a1c(), 77 );
b.b8cref( 79 )
self.assertEqual( b.b7().a1c(), 79 );
b.set_an_cref( 79 )
self.assertEqual( b.amember_cptr().a1c(), 79 );
aref = b.b7()
aref = b.amember_cptr()
err_caught = False
if not leak_check:
try:
x = aref.a1() # cannot call non-const method on const reference (as delivered by b7)
x = aref.a1() # cannot call non-const method on const reference (as delivered by amember_cptr)
except:
err_caught = True
self.assertEqual( err_caught, True )
self.assertEqual( aref.a1c(), 79 );
b.b8( -1 )
b.set_an( -1 )
self.assertEqual( aref.a1c(), -1 );
def test_19(self):
@ -1068,19 +1076,19 @@ class BasicTest(unittest.TestCase):
b = pya.B()
a1 = b.b14a( True )
a2 = b.b14b()
a1 = b.amember_or_nil_alt( True )
a2 = b.amember_ptr_alt()
self.assertEqual( a1.a1(), 17 )
self.assertEqual( a2.a1(), 17 )
a1.a5( 761 )
self.assertEqual( a1.a1(), 761 )
self.assertEqual( a2.a1(), 761 )
a1 = b.b14a( False )
a1 = b.amember_or_nil( False )
self.assertEqual( a1, None )
self.assertEqual( b.b15( b.b14b() ), True )
self.assertEqual( b.b15( b.b14a( False ) ), False )
self.assertEqual( b.b15( b.amember_ptr() ), True )
self.assertEqual( b.b15( b.amember_or_nil( False ) ), False )
self.assertEqual( b.b15( None ), False )
def test_21(self):
@ -1094,9 +1102,9 @@ class BasicTest(unittest.TestCase):
b = pya.B()
# b14b() returns a pya.A object, but it cannot be extended dynamically by a method s ...
b.b14b().s( 117 )
self.assertEqual( b.b14b().g(), 117 )
# amember_ptr() returns a pya.A object, but it cannot be extended dynamically by a method s ...
b.amember_ptr().s( 117 )
self.assertEqual( b.amember_ptr().g(), 117 )
n = 0
@ -1247,9 +1255,9 @@ class BasicTest(unittest.TestCase):
self.assertEqual( b.bx("a", 15), 20.5 )
self.assertEqual( b.b32("b", 25), 20.5 )
na = pya.A.a0() # instance count
na = pya.A.instance_count() # instance count
self.assertEqual(b.bx(a, 15), "aref+i")
self.assertEqual(pya.A.a0(), na)
self.assertEqual(pya.A.instance_count(), na)
err_caught = False
try:
# cannot cast second argument to int
@ -1258,7 +1266,7 @@ class BasicTest(unittest.TestCase):
err_caught = True
self.assertEqual(err_caught, True)
# the exception thrown before must not leave an instance on the call stack:
self.assertEqual(pya.A.a0(), na)
self.assertEqual(pya.A.instance_count(), na)
err_caught = False
try:
@ -1368,52 +1376,52 @@ class BasicTest(unittest.TestCase):
# destruction of an instance via c++
pya.A.a20(None)
ac0 = pya.A.a0()
ic0 = pya.A.instance_count()
a = pya.A()
a.create()
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(a) # install static instance of A
self.assertEqual(a.destroyed(), False)
pya.A.a20(None)
self.assertEqual(a.destroyed(), True)
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
a = pya.A()
a.create()
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(a) # install static instance of A
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(a) # re-install static instance of A
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
# install another instance
aa = pya.A()
aa.create()
self.assertEqual(aa.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 2)
self.assertEqual(pya.A.instance_count(), ic0 + 2)
pya.A.a20(aa) # install static instance of A
# original one is destroyed now, only new instance remains
self.assertEqual(a.destroyed(), True)
self.assertEqual(aa.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(None) # discard installed instance
self.assertEqual(aa.destroyed(), True)
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
# the same without create .. should work too, but not create an instance because of late
# instantiation in default ctor
a = pya.A()
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
pya.A.a20(a) # install static instance of A
self.assertEqual(a.destroyed(), False)
pya.A.a20(None)
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
self.assertEqual(a.destroyed(), True)
def test_26(self):
@ -1463,36 +1471,36 @@ class BasicTest(unittest.TestCase):
# destruction of an instance via c++
pya.A.a20(None)
ac0 = pya.A.a0()
ic0 = pya.A.instance_count()
a = pya.A()
a._create()
self.assertEqual(a._destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(a)
self.assertEqual(pya.A.a20_get() == None, False)
# release A instance -> will delete it
a = None
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
self.assertEqual(pya.A.a20_get() == None, True)
a = pya.A()
a._create()
self.assertEqual(a.destroyed(), False)
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
pya.A.a20(a) # install static instance of A
self.assertEqual(pya.A.a20_get() == None, False)
a._unmanage()
# release A instance -> won't delete it since it is unmanaged
a = None
self.assertEqual(pya.A.a0(), ac0 + 1)
self.assertEqual(pya.A.instance_count(), ic0 + 1)
self.assertEqual(pya.A.a20_get() == None, False)
a = pya.A.a20_get()
a._manage()
# release A instance -> will be deleted since now it's managed again
a = None
self.assertEqual(pya.A.a0(), ac0)
self.assertEqual(pya.A.instance_count(), ic0)
self.assertEqual(pya.A.a20_get() == None, True)
def test_28(self):

View File

@ -14,11 +14,11 @@ class Basic_TestClass < TestBase
GC.start
# all references of A are released now:
ac0 = RBA::A::a0
assert_equal( ac0, 0 )
ic0 = RBA::A::instance_count
assert_equal( ic0, 0 )
a = RBA::A.new_a(100)
assert_equal( RBA::A::a0, ac0 + 1 )
assert_equal( RBA::A::instance_count, ic0 + 1 )
a = RBA::A.new
assert_equal(a.a1, 17)
@ -27,26 +27,26 @@ class Basic_TestClass < TestBase
a = nil
GC.start
assert_equal( RBA::A::a0, ac0 )
assert_equal( RBA::A::instance_count, ic0 )
a = RBA::A.new
assert_equal( RBA::A::a0, ac0 ) # delayed instantiation of detached objects - A is actually created if it is used first
assert_equal( RBA::A::instance_count, ic0 ) # delayed instantiation of detached objects - A is actually created if it is used first
a.a2 # just check, if it can be called
assert_equal( RBA::A::a0, ac0 + 1 )
assert_equal( RBA::A::instance_count, ic0 + 1 )
# open question: with ruby 1.8, aa is not deleted if the assert_equal is missing. Why?
# maybe the GC does not like to be called that frequently?
aa = a.dup
assert_equal( RBA::A::a0, ac0 + 2 )
assert_equal( RBA::A::instance_count, ic0 + 2 )
aa = nil
GC.start
if RUBY_VERSION >= "1.9.0"
# GC works differently in >=1.9.x - but no leak (verified with valgrind)
ac0 = RBA::A::a0
ic0 = RBA::A::instance_count
else
assert_equal( RBA::A::a0, ac0 + 1 )
assert_equal( RBA::A::instance_count, ic0 + 1 )
end
a = nil
@ -54,15 +54,15 @@ class Basic_TestClass < TestBase
if RUBY_VERSION >= "1.9.0"
# GC works differently in >=1.9.x - but no leak (verified with valgrind)
ac0 = RBA::A::a0
ic0 = RBA::A::instance_count
else
assert_equal( RBA::A::a0, ac0 )
assert_equal( RBA::A::instance_count, ic0 )
end
a = RBA::A.new
assert_equal( RBA::A::a0, ac0 ) # delayed instantiation of detached objects - A is actually created if it is used first
assert_equal( RBA::A::instance_count, ic0 ) # delayed instantiation of detached objects - A is actually created if it is used first
a.a2 # just check, if it can be called
assert_equal( RBA::A::a0, ac0 + 1 )
assert_equal( RBA::A::instance_count, ic0 + 1 )
# mix of getters, setters, predicates
assert_equal( a.af, false )
@ -116,7 +116,7 @@ class Basic_TestClass < TestBase
assert_equal(arr, [5, 1, -1.25])
a.destroy
assert_equal( RBA::A::a0, ac0 )
assert_equal( RBA::A::instance_count, ic0 )
if !$leak_check
@ -138,13 +138,13 @@ class Basic_TestClass < TestBase
end
assert_equal( RBA::A::a0, ac0 )
assert_equal( RBA::A::instance_count, ic0 )
a = RBA::A::new_a( 55 )
assert_equal( RBA::A::a0, ac0 + 1 )
assert_equal( RBA::A::instance_count, ic0 + 1 )
assert_equal( a.a1, 55 )
assert_equal( a.a_vp1( a.a_vp2 ), "abc" )
a.destroy
assert_equal( RBA::A::a0, ac0 )
assert_equal( RBA::A::instance_count, ic0 )
a = RBA::A::new_a(0)
assert_equal( a.a9a(5).to_s, "true" )
@ -506,7 +506,7 @@ class Basic_TestClass < TestBase
err_caught = false
begin
b.b7.a1 # cannot call non-const method on const reference
b.amember_cptr.a1 # cannot call non-const method on const reference
rescue
err_caught = true
end
@ -514,7 +514,7 @@ class Basic_TestClass < TestBase
end
b.b7.a2
b.amember_cptr.a2
assert_equal( b.b1, 5 )
assert_equal( b.b2, "" )
@ -857,46 +857,57 @@ class Basic_TestClass < TestBase
# test copies of objects being returned
b = RBA::B.new
b._create
a = b.b6( 1971 );
assert_equal( a.a1, 1971 );
assert_equal( b.b9( a ), 1971 );
GC.start
a_count = RBA::A.instance_count
a = b.make_a( 1971 );
assert_equal( RBA::A.instance_count, a_count + 1 )
aa = b.b6( -61 );
assert_equal( b.b9cref( aa ), -61 );
assert_equal( a.a1, 1971 );
assert_equal( b.b9( a ), 1971 );
assert_equal( b.an( a ), 1971 );
aa = b.make_a( -61 );
assert_equal( RBA::A.instance_count, a_count + 2 )
assert_equal( b.an_cref( aa ), -61 );
assert_equal( a.a1, 1971 );
assert_equal( b.an( a ), 1971 );
assert_equal( aa.a1, -61 );
assert_equal( b.b9( aa ), -61 );
assert_equal( b.an( aa ), -61 );
aa.a5 98;
a.a5 100;
assert_equal( a.a1, 100 );
assert_equal( b.b9( a ), 100 );
assert_equal( b.an( a ), 100 );
assert_equal( aa.a1, 98 );
assert_equal( b.b9( aa ), 98 );
assert_equal( b.an( aa ), 98 );
a._destroy
aa = nil
GC.start
assert_equal( RBA::A.instance_count, a_count )
end
def test_18
# Test references to objects (returned by b.b7)
# Test references to objects (returned by b.amember_cptr)
b = RBA::B.new
b.b8( 77 )
assert_equal( b.b7.a1c, 77 );
b.set_an( 77 )
assert_equal( b.amember_cptr.a1c, 77 );
b.b8cref( 79 )
assert_equal( b.b7.a1c, 79 );
b.set_an_cref( 79 )
assert_equal( b.amember_cptr.a1c, 79 );
aref = b.b7
aref = b.amember_cptr
err_caught = false
if !$leak_check
begin
x = aref.a1 # cannot call non-const method on const reference (as delivered by b7)
x = aref.a1 # cannot call non-const method on const reference (as delivered by amember_cptr)
rescue
err_caught = true
end
@ -905,7 +916,7 @@ class Basic_TestClass < TestBase
end
b.b8( -1 )
b.set_an( -1 )
assert_equal( aref.a1c, -1 );
end
@ -973,19 +984,19 @@ class Basic_TestClass < TestBase
b = RBA::B.new
a1 = b.b14a( true )
a2 = b.b14b
a1 = b.amember_or_nil( true )
a2 = b.amember_ptr
assert_equal( a1.a1, 17 )
assert_equal( a2.a1, 17 )
a1.a5( 761 )
assert_equal( a1.a1, 761 )
assert_equal( a2.a1, 761 )
a1 = b.b14a( false )
a1 = b.amember_or_nil( false )
assert_equal( a1, nil )
assert_equal( b.b15( b.b14b ), true )
assert_equal( b.b15( b.b14a( false ) ), false )
assert_equal( b.b15( b.amember_ptr ), true )
assert_equal( b.b15( b.amember_or_nil( false ) ), false )
assert_equal( b.b15( nil ), false )
end
@ -996,8 +1007,8 @@ class Basic_TestClass < TestBase
b = RBA::B.new
b.b14b.s( 117 )
assert_equal( b.b14b.g, 117 )
b.amember_ptr.s( 117 )
assert_equal( b.amember_ptr.g, 117 )
n = 0
b.b10_nc { |a| a.s( n ); n += 1 }
@ -1138,10 +1149,10 @@ class Basic_TestClass < TestBase
assert_equal( b.b32( "b", 25 ), 20.5 )
GC.start
na = RBA::A::a0 # instance count
na = RBA::A::instance_count # instance count
assert_equal( b.bx( a, 15 ), "aref+i" )
GC.start
assert_equal( RBA::A::a0, na )
assert_equal( RBA::A::instance_count, na )
err_caught = false
begin
# cannot cast second argument to int
@ -1152,7 +1163,7 @@ class Basic_TestClass < TestBase
assert_equal( err_caught, true )
# the exception thrown before must not leave an instance on the call stack:
GC.start
assert_equal( RBA::A::a0, na )
assert_equal( RBA::A::instance_count, na )
err_caught = false
begin
@ -1254,53 +1265,53 @@ class Basic_TestClass < TestBase
# destruction of an instance via c++
GC.start
ac0 = RBA::A.a0
ic0 = RBA::A.instance_count
a = RBA::A::new
a.create
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(a) # install static instance of A
assert_equal(a.destroyed?, false)
RBA::A.a20(nil)
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
assert_equal(a.destroyed?, true)
a = RBA::A::new
a.create
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(a) # install static instance of A
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(a) # re-install static instance of A
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
# install another instance
aa = RBA::A::new
aa.create
assert_equal(aa.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 2)
assert_equal(RBA::A.instance_count, ic0 + 2)
RBA::A.a20(aa) # install static instance of A
# original one is destroyed now, only new instance remains
assert_equal(a.destroyed?, true)
assert_equal(aa.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(nil) # discard installed instance
assert_equal(aa.destroyed, true)
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
# the same without create .. should work too, but not create an instance because of late
# instantiation in default ctor
a = RBA::A::new
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
RBA::A.a20(a) # install static instance of A
assert_equal(a.destroyed?, false)
RBA::A.a20(nil)
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
assert_equal(a.destroyed?, true)
end
@ -1309,13 +1320,13 @@ class Basic_TestClass < TestBase
# destruction of an instance via c++
GC.start
ac0 = RBA::A.a0
ic0 = RBA::A.instance_count
1.times do
a = RBA::A::new
a._create
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(a) # install static instance of A
assert_equal(RBA::A.a20_get == nil, false)
end
@ -1323,7 +1334,7 @@ class Basic_TestClass < TestBase
# makes sure the objects inside the block before are deleted
GC.start
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
assert_equal(RBA::A.a20_get == nil, true)
# "unmanage" will freeze the object and not make it destroyed by the GC
@ -1331,7 +1342,7 @@ class Basic_TestClass < TestBase
a = RBA::A::new
a._create
assert_equal(a.destroyed?, false)
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
RBA::A.a20(a) # install static instance of A
assert_equal(RBA::A.a20_get == nil, false)
a._unmanage
@ -1340,7 +1351,7 @@ class Basic_TestClass < TestBase
# makes sure the objects inside the block before are deleted
GC.start
assert_equal(RBA::A.a0, ac0 + 1)
assert_equal(RBA::A.instance_count, ic0 + 1)
assert_equal(RBA::A.a20_get == nil, false)
# after "manage" the object gets volatile again
@ -1352,7 +1363,7 @@ class Basic_TestClass < TestBase
# makes sure the objects inside the block before are deleted
GC.start
assert_equal(RBA::A.a0, ac0)
assert_equal(RBA::A.instance_count, ic0)
assert_equal(RBA::A.a20_get == nil, true)
end
@ -1786,7 +1797,7 @@ class Basic_TestClass < TestBase
assert_equal(1, yy.size)
assert_equal("RBA::Y", yy[0].class.to_s)
assert_equal(true, yy[0] != nil)
yy[0].destroy
yy[0]._destroy
assert_equal(true, yy[0].destroyed?)
assert_equal(yc, y.vx_dyn_count)