Skip to content

Commit 440f57d

Browse files
committed
Windows Build Script and Associated Documentation Per Platform
1 parent 779798d commit 440f57d

File tree

4 files changed

+303
-110
lines changed

4 files changed

+303
-110
lines changed

README.md

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,58 @@ This package also supports most of FCL's object shapes, including:
2727

2828
## Installation
2929

30-
First, install [octomap](https://github.com/OctoMap/octomap), which is necessary using OcTree. For Ubuntu, using `sudo apt-get install liboctomap-dev`
31-
Second, install FCL using the instructions provided [here](https://github.com/flexible-collision-library/fcl).
32-
If you're on Ubuntu 17.04 or newer, you can install FCL using `sudo apt-get install libfcl-dev`.
33-
Otherwise, just compile FCL from source -- it's quick and easy, and its dependencies are all easily installed via `apt` or `brew`.
34-
35-
In order to install the Python wrappers for FCL, simply run
36-
```shell
37-
pip install python-fcl
30+
### Linux
31+
32+
First install needed dependencies:
33+
34+
```bash
35+
sudo apt-get install liboctomap-dev libfcl-dev
36+
```
37+
38+
Then install for your particular Python version:
39+
40+
```bash
41+
pip3 install python-fcl
3842
```
3943

44+
### MacOS
45+
46+
First install needed dependencies:
47+
48+
```bash
49+
brew install fcl eigen octomap libccd
50+
```
51+
52+
Then install for your particular Python version:
53+
54+
```bash
55+
pip3 install python-fcl
56+
```
57+
58+
### Windows
59+
60+
Building on Windows requires:
61+
62+
* Python3 (e.g. Not tested using Python2)
63+
* Cython
64+
* CMake
65+
* MSVC (Visual Studio 16 2019)
66+
67+
> Since the build script places artifacts in `C:\Program Files (x86)`, it is
68+
necessary to run it using an "Administrator PowerShell" prompt.
69+
70+
```bash
71+
# Run using Administrator PowerShell prompt. WILL FAIL WITHOUT PROPER ACCESS
72+
73+
git clone https://github.com/BerkeleyAutomation/python-fcl
74+
cd python-fcl
75+
76+
# Use CMake to compile/install all dependencies along with installing python-fcl
77+
requirements/build_win32.ps1
78+
```
79+
80+
# Usage Examples
81+
4082
## Objects
4183

4284
### Collision Objects

example/example.py

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,29 @@
1+
from __future__ import print_function
12
import numpy as np
23
import fcl
34

45
def print_collision_result(o1_name, o2_name, result):
5-
print 'Collision between {} and {}:'.format(o1_name, o2_name)
6-
print '-'*30
7-
print 'Collision?: {}'.format(result.is_collision)
8-
print 'Number of contacts: {}'.format(len(result.contacts))
9-
print ''
6+
print('Collision between {} and {}:'.format(o1_name, o2_name))
7+
print('-'*30)
8+
print('Collision?: {}'.format(result.is_collision))
9+
print('Number of contacts: {}'.format(len(result.contacts)))
10+
print()
1011

1112
def print_continuous_collision_result(o1_name, o2_name, result):
12-
print 'Continuous collision between {} and {}:'.format(o1_name, o2_name)
13-
print '-'*30
14-
print 'Collision?: {}'.format(result.is_collide)
15-
print 'Time of collision: {}'.format(result.time_of_contact)
16-
print ''
13+
print('Continuous collision between {} and {}:'.format(o1_name, o2_name))
14+
print('-'*30)
15+
print('Collision?: {}'.format(result.is_collide))
16+
print('Time of collision: {}'.format(result.time_of_contact))
17+
print()
1718

1819
def print_distance_result(o1_name, o2_name, result):
19-
print 'Distance between {} and {}:'.format(o1_name, o2_name)
20-
print '-'*30
21-
print 'Distance: {}'.format(result.min_distance)
22-
print 'Closest Points:'
23-
print result.nearest_points[0]
24-
print result.nearest_points[1]
25-
print ''
20+
print('Distance between {} and {}:'.format(o1_name, o2_name))
21+
print('-'*30)
22+
print('Distance: {}'.format(result.min_distance))
23+
print('Closest Points:')
24+
print(result.nearest_points[0])
25+
print(result.nearest_points[1])
26+
print()
2627

2728
# Create simple geometries
2829
box = fcl.Box(1.0, 2.0, 3.0)
@@ -48,10 +49,10 @@ def print_distance_result(o1_name, o2_name, result):
4849
#=====================================================================
4950
# Pairwise collision checking
5051
#=====================================================================
51-
print '='*60
52-
print 'Testing Pairwise Collision Checking'
53-
print '='*60
54-
print ''
52+
print('='*60)
53+
print('Testing Pairwise Collision Checking')
54+
print('='*60)
55+
print()
5556

5657
req = fcl.CollisionRequest(enable_contact=True)
5758
res = fcl.CollisionResult()
@@ -74,10 +75,10 @@ def print_distance_result(o1_name, o2_name, result):
7475
#=====================================================================
7576
# Pairwise distance checking
7677
#=====================================================================
77-
print '='*60
78-
print 'Testing Pairwise Distance Checking'
79-
print '='*60
80-
print ''
78+
print('='*60)
79+
print('Testing Pairwise Distance Checking')
80+
print('='*60)
81+
print()
8182

8283
req = fcl.DistanceRequest(enable_nearest_points=True)
8384
res = fcl.DistanceResult()
@@ -100,10 +101,10 @@ def print_distance_result(o1_name, o2_name, result):
100101
#=====================================================================
101102
# Pairwise continuous collision checking
102103
#=====================================================================
103-
print '='*60
104-
print 'Testing Pairwise Continuous Collision Checking'
105-
print '='*60
106-
print ''
104+
print('='*60)
105+
print('Testing Pairwise Continuous Collision Checking')
106+
print('='*60)
107+
print()
107108

108109
req = fcl.ContinuousCollisionRequest()
109110
res = fcl.ContinuousCollisionResult()
@@ -118,10 +119,10 @@ def print_distance_result(o1_name, o2_name, result):
118119
#=====================================================================
119120
# Managed collision checking
120121
#=====================================================================
121-
print '='*60
122-
print 'Testing Managed Collision and Distance Checking'
123-
print '='*60
124-
print ''
122+
print('='*60)
123+
print('Testing Managed Collision and Distance Checking')
124+
print('='*60)
125+
print('')
125126
objs1 = [fcl.CollisionObject(box, fcl.Transform(np.array([20,0,0]))), fcl.CollisionObject(sphere)]
126127
objs2 = [fcl.CollisionObject(cone), fcl.CollisionObject(mesh)]
127128
objs3 = [fcl.CollisionObject(box), fcl.CollisionObject(sphere)]
@@ -143,26 +144,26 @@ def print_distance_result(o1_name, o2_name, result):
143144
#=====================================================================
144145
cdata = fcl.CollisionData()
145146
manager1.collide(cdata, fcl.defaultCollisionCallback)
146-
print 'Collision within manager 1?: {}'.format(cdata.result.is_collision)
147-
print ''
147+
print('Collision within manager 1?: {}'.format(cdata.result.is_collision))
148+
print()
148149

149150
cdata = fcl.CollisionData()
150151
manager2.collide(cdata, fcl.defaultCollisionCallback)
151-
print 'Collision within manager 2?: {}'.format(cdata.result.is_collision)
152-
print ''
152+
print('Collision within manager 2?: {}'.format(cdata.result.is_collision))
153+
print()
153154

154155
##=====================================================================
155156
## Managed internal (n^2) distance checking
156157
##=====================================================================
157158
ddata = fcl.DistanceData()
158159
manager1.distance(ddata, fcl.defaultDistanceCallback)
159-
print 'Closest distance within manager 1?: {}'.format(ddata.result.min_distance)
160-
print ''
160+
print('Closest distance within manager 1?: {}'.format(ddata.result.min_distance))
161+
print()
161162

162163
ddata = fcl.DistanceData()
163164
manager2.distance(ddata, fcl.defaultDistanceCallback)
164-
print 'Closest distance within manager 2?: {}'.format(ddata.result.min_distance)
165-
print ''
165+
print('Closest distance within manager 2?: {}'.format(ddata.result.min_distance))
166+
print()
166167

167168
#=====================================================================
168169
# Managed one to many collision checking
@@ -171,20 +172,19 @@ def print_distance_result(o1_name, o2_name, result):
171172
rdata = fcl.CollisionData(request = req)
172173

173174
manager1.collide(fcl.CollisionObject(mesh), rdata, fcl.defaultCollisionCallback)
174-
print 'Collision between manager 1 and Mesh?: {}'.format(rdata.result.is_collision)
175-
print 'Contacts:'
175+
print('Collision between manager 1 and Mesh?: {}'.format(rdata.result.is_collision))
176+
print('Contacts:')
176177
for c in rdata.result.contacts:
177-
print '\tO1: {}, O2: {}'.format(c.o1, c.o2)
178-
print ''
178+
print('\tO1: {}, O2: {}'.format(c.o1, c.o2))
179+
print()
179180

180181
#=====================================================================
181182
# Managed many to many collision checking
182183
#=====================================================================
183184
rdata = fcl.CollisionData(request = req)
184185
manager3.collide(manager2, rdata, fcl.defaultCollisionCallback)
185-
print 'Collision between manager 2 and manager 3?: {}'.format(rdata.result.is_collision)
186-
print 'Contacts:'
186+
print('Collision between manager 2 and manager 3?: {}'.format(rdata.result.is_collision))
187+
print('Contacts:')
187188
for c in rdata.result.contacts:
188-
print '\tO1: {}, O2: {}'.format(c.o1, c.o2)
189-
print ''
190-
189+
print('\tO1: {}, O2: {}'.format(c.o1, c.o2))
190+
print()

requirements/build_win32.ps1

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
<#
2+
This script builds fcl and it's dependencies for python-fcl on Windows.
3+
4+
It downloads, builds, installs, and then deletes:
5+
* fcl
6+
* libccd
7+
* eigen
8+
* octomap
9+
#>
10+
11+
# Ensure that paths are constant between runs
12+
pushd $PSScriptRoot
13+
14+
# Create a directory that encapsulates all Git repos
15+
mkdir fcl; cd fcl
16+
17+
18+
#------------------------------------------------------------------------------
19+
# Eigen
20+
Write-Host "Building Eigen"
21+
git clone https://gitlab.com/libeigen/eigen.git
22+
cd eigen
23+
mkdir build; cd build
24+
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..
25+
cmake --build . --config Release --target install
26+
Write-Host "Done"
27+
cd ../..
28+
29+
30+
# ------------------------------------------------------------------------------
31+
# LibCCD
32+
Write-Host "Building LibCCD"
33+
git clone https://github.com/danfis/libccd
34+
cd libccd
35+
mkdir build; cd build
36+
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..
37+
cmake --build . --config Release --target install
38+
Write-Host "Done"
39+
cd ../..
40+
41+
# FCL won't be able to find libccd unless it is named "ccd" exactly
42+
Rename-Item "C:\Program Files (x86)\libccd" ccd
43+
44+
45+
# ------------------------------------------------------------------------------
46+
# Octomap
47+
Write-Host "Building Octomap"
48+
git clone https://github.com/OctoMap/octomap
49+
cd octomap
50+
mkdir build; cd build
51+
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" -DBUILD_SHARED_LIBS=ON ..
52+
53+
# Build Octomap (won't install for some reason)
54+
cmake --build . --config Release --target install
55+
56+
# Now rebuild, which installs correctly
57+
cmake --build . --config Release --target install
58+
Write-Host "Done"
59+
cd ../../
60+
61+
# FCL won't be able to find octomap unless it is named "octomap" exactly
62+
Rename-Item "C:\Program Files (x86)\octomap-distribution" octomap
63+
64+
65+
# ------------------------------------------------------------------------------
66+
# FCL
67+
Write-Host "Building FCL"
68+
git clone https://github.com/flexible-collision-library/fcl
69+
cd fcl
70+
71+
# Checkout specific version 0.5.0 (only one compatible with python-fcl)
72+
git checkout 7075caf32ddcd5825ff67303902e3db7664a407a
73+
mkdir build; cd build
74+
75+
# Fiddle with build file to help fcl find LibCCD and Octomap
76+
# Also tells compiler to dynamically link with C runtime (matches Cython)
77+
$build_script_modification = @"
78+
find_package(ccd QUIET)
79+
find_package(octomap QUIET)
80+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL$<$<CONFIG:Debug>:Debug>")
81+
"@
82+
$filePath = "../CMakeLists.txt"
83+
$lineNumber = 11
84+
$fileContent = Get-Content $filePath
85+
$fileContent[$lineNumber-1] = $build_script_modification
86+
$fileContent | Set-Content $filePath
87+
88+
# Now perform actual build
89+
cmake -DCMAKE_BUILD_TYPE=Release -G "Visual Studio 16 2019" ..
90+
cmake --build . --config Release --target install
91+
Write-Host "Done"
92+
cd ../../
93+
94+
95+
# ------------------------------------------------------------------------------
96+
# Python-FCL
97+
cd ../
98+
99+
# Delete compilation directory since it is no longer needed
100+
del -Force -Recurse fcl
101+
102+
cd ../
103+
104+
# Now build Cython extension
105+
python setup.py install
106+
Write-Host "Successfully built python-fcl"
107+
108+
# At this point, you cannot import fcl directly in Python because it will fail.
109+
# This is because it doesn't have the required DLLs. Let's fix that:
110+
# NOTE: The default SourceFileLoader will find python-fcl's `fcl` package. So
111+
# let's create a tmp directory and use that to force it to find the one in the
112+
# `site-packages`'s directory.
113+
mkdir tmp; cd tmp
114+
$fcl_dir = $(python -c "import pathlib as p, pkgutil as pk; print(p.Path(pk.get_loader('fcl').get_filename()).parent)")
115+
Write-Host "Installed into: $fcl_dir. Copying dependent DLLs"
116+
ls "C:/Program Files (x86)/octomap/bin/*.dll" | cp -destination $fcl_dir
117+
cp "C:/Program Files (x86)/ccd/bin/ccd.dll" $fcl_dir
118+
119+
# Now delete all of the installed dependencies (after building python-fcl)
120+
Write-Host "Removing build directories for Eigen, LibCCD, FCL, and Octomap"
121+
rmdir -r 'C:\Program Files (x86)\Eigen3'
122+
rmdir -r 'C:\Program Files (x86)\ccd'
123+
rmdir -r 'C:\Program Files (x86)\fcl'
124+
rmdir -r 'C:\Program Files (x86)\octomap'
125+
126+
Write-Host "All done!"
127+
128+
# Make sure to return the cwd to wherever it was before the build
129+
popd

0 commit comments

Comments
 (0)