Skip to content

Commit

Permalink
Merge pull request canonical#204 from kyrofa/ld_library_path_opengl
Browse files Browse the repository at this point in the history
Add support for mesa libraries.
  • Loading branch information
sergiusens committed Jan 7, 2016
2 parents 88c8f2b + 5528b1b commit d0ab400
Show file tree
Hide file tree
Showing 8 changed files with 221 additions and 19 deletions.
14 changes: 14 additions & 0 deletions examples/opencv/snapcraft.yaml
@@ -0,0 +1,14 @@
name: opencv-example
version: 1.0
summary: Use OpenCV and OpenGL
description: A simple OpenCV example

binaries:
example:
exec: bin/example

parts:
example:
plugin: cmake
source: src
stage-packages: [libopencv-dev]
10 changes: 10 additions & 0 deletions examples/opencv/src/CMakeLists.txt
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 2.6)
project(example)

find_package(OpenCV REQUIRED)

add_executable(example main.cpp)

target_link_libraries(example ${OpenCV_LIBS})

install(TARGETS example RUNTIME DESTINATION bin)
15 changes: 15 additions & 0 deletions examples/opencv/src/main.cpp
@@ -0,0 +1,15 @@
#include <iostream>

#include <opencv2/core/core.hpp>

int main()
{
cv::Mat matrix(2, 2, CV_8UC1);

matrix.at<uint8_t>(cv::Point(0, 0)) = 1;
matrix.at<uint8_t>(cv::Point(0, 1)) = 2;
matrix.at<uint8_t>(cv::Point(1, 0)) = 3;
matrix.at<uint8_t>(cv::Point(1, 1)) = 4;

std::cout << matrix << std::endl;
}
5 changes: 5 additions & 0 deletions examples_tests/tests.py
Expand Up @@ -125,6 +125,11 @@ class TestSnapcraftExamples(testscenarios.TestWithScenarios):
'custom libpipeline called\n'
'include\n')],
}),
('opencv', {
'dir': 'opencv',
'name': 'opencv-example',
'version': '1.0',
}),
('py2-project', {
'dir': 'py2-project',
'name': 'spongeshaker',
Expand Down
50 changes: 50 additions & 0 deletions snapcraft/libraries.py
@@ -0,0 +1,50 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2016 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import re
import glob


def determine_ld_library_path(root):
# If more ld.so.conf files need to be supported, add them here.
ld_config_globs = {
'{}/usr/lib/*/mesa*/ld.so.conf'.format(root)
}

ld_library_paths = []
for this_glob in ld_config_globs:
for ld_conf_file in glob.glob(this_glob):
ld_library_paths.extend(_extract_ld_library_paths(ld_conf_file))

return [root + path for path in ld_library_paths]


def _extract_ld_library_paths(ld_conf_file):
# From the ldconfig manpage, paths can be colon-, space-, tab-, newline-,
# or comma-separated.
path_delimiters = re.compile(r'[:\s,]')
comments = re.compile(r'#.*$')

paths = []
with open(ld_conf_file, 'r') as f:
for line in f:
# Remove comments from line
line = comments.sub('', line).strip()

if line:
paths.extend(path_delimiters.split(line))

return paths
45 changes: 45 additions & 0 deletions snapcraft/tests/test_libraries.py
@@ -0,0 +1,45 @@
# -*- Mode:Python; indent-tabs-mode:nil; tab-width:4 -*-
#
# Copyright (C) 2016 Canonical Ltd
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import os
import tempfile

from snapcraft import (
libraries,
tests,
)


class TestLdLibraryPathParser(tests.TestCase):

def _write_conf_file(self, contents):
tmp = tempfile.NamedTemporaryFile(delete=False, mode='w')
self.addCleanup(os.remove, tmp.name)

tmp.write(contents)
tmp.close()

return tmp.name

def test_extract_ld_library_paths(self):
file_path = self._write_conf_file("""# This is a comment
/foo/bar
/colon:/separated,/comma\t/tab /space # This is another comment
/baz""")

self.assertEqual(['/foo/bar', '/colon', '/separated', '/comma',
'/tab', '/space', '/baz'],
libraries._extract_ld_library_paths(file_path))
91 changes: 72 additions & 19 deletions snapcraft/tests/test_yaml.py
Expand Up @@ -16,12 +16,12 @@

import logging
import os
import tempfile
import unittest
import unittest.mock

import fixtures

import snapcraft.common
import snapcraft.yaml
from snapcraft import (
dirs,
Expand All @@ -40,21 +40,13 @@ def setUp(self):
mock_wrap_exe.return_value = True
self.addCleanup(patcher.stop)

def make_snapcraft_yaml(self, content, encoding='ascii'):
tempdirObj = tempfile.TemporaryDirectory()
self.addCleanup(tempdirObj.cleanup)
os.chdir(tempdirObj.name)
with open('snapcraft.yaml', 'w', encoding=encoding) as fp:
fp.write(content)

@unittest.mock.patch('snapcraft.yaml.Config.load_plugin')
@unittest.mock.patch('snapcraft.wiki.Wiki.get_part')
def test_config_loads_plugins(self, mock_get_part, mock_loadPlugin):
self.make_snapcraft_yaml("""name: test
version: "1"
summary: test
description: test
icon: my-icon.png
parts:
part1:
Expand All @@ -77,7 +69,6 @@ def test_config_loads_with_different_encodings(
version: "1"
summary: test
description: ñoño test
icon: my-icon.png
parts:
part1:
Expand All @@ -103,7 +94,6 @@ def test_config_loads_part_from_wiki(self, mock_compose, mock_loadPlugin):
version: "1"
summary: test
description: test
icon: my-icon.png
parts:
part1:
Expand All @@ -126,7 +116,6 @@ def test_config_with_wiki_part_after(self, mock_get_part, mock_load):
version: "1"
summary: test
description: test
icon: my-icon.png
parts:
part1:
Expand Down Expand Up @@ -179,7 +168,6 @@ def test_config_loop(self):
version: "1"
summary: test
description: test
icon: my-icon.png
parts:
p1:
Expand Down Expand Up @@ -207,7 +195,6 @@ def test_invalid_yaml_missing_name(self, mock_loadPlugin):
version: "1"
summary: test
description: nothing
icon: my-icon.png
parts:
part1:
Expand All @@ -229,7 +216,6 @@ def test_invalid_yaml_invalid_name_as_number(self, mock_loadPlugin):
version: "1"
summary: test
description: nothing
icon: my-icon.png
parts:
part1:
Expand All @@ -251,7 +237,6 @@ def test_invalid_yaml_invalid_name_chars(self, mock_loadPlugin):
version: "1"
summary: test
description: nothing
icon: my-icon.png
parts:
part1:
Expand All @@ -273,7 +258,6 @@ def test_invalid_yaml_missing_description(self, mock_loadPlugin):
self.make_snapcraft_yaml("""name: test
version: "1"
summary: test
icon: my-icon.png
parts:
part1:
Expand All @@ -295,7 +279,6 @@ def test_tab_in_yaml(self, mock_loadPlugin):
self.make_snapcraft_yaml("""name: test
version: "1"
\tsummary: test
icon: my-icon.png
parts:
part1:
Expand All @@ -317,7 +300,6 @@ def test_config_expands_filesets(self, mock_loadPlugin):
version: "1"
summary: test
description: test
icon: my-icon.png
parts:
part1:
Expand Down Expand Up @@ -346,6 +328,77 @@ def test_config_expands_filesets(self, mock_loadPlugin):
})


class TestYamlEnvironment(tests.TestCase):

def setUp(self):
super().setUp()
dirs.setup_dirs()

self.make_snapcraft_yaml("""name: test
version: "1"
summary: test
description: test
parts:
part1:
plugin: go
stage-packages: [fswebcam]
""")

def test_config_runtime_environment(self):
config = snapcraft.yaml.Config()
environment = config.runtime_env('foo')
self.assertTrue('PATH="foo/bin:foo/usr/bin:$PATH"' in environment)

# Ensure that LD_LIBRARY_PATH is present and it contains only the
# basics.
paths = []
for variable in environment:
if 'LD_LIBRARY_PATH' in variable:
these_paths = variable.split('=')[1].strip()
paths.extend(these_paths.replace('"', '').split(':'))

self.assertTrue(len(paths) > 0,
'Expected LD_LIBRARY_PATH to be in environment')

arch = snapcraft.common.get_arch_triplet()
for expected in ['foo/lib', 'foo/usr/lib', 'foo/lib/{}'.format(arch),
'foo/usr/lib/{}'.format(arch)]:
self.assertTrue(expected in paths,
'Expected LD_LIBRARY_PATH to include "{}"'.format(
expected))

def test_config_runtime_environment_ld(self):
# Place a few ld.so.conf files in supported locations. We expect the
# contents of these to make it into the LD_LIBRARY_PATH.
os.makedirs('foo/usr/lib/my_arch/mesa/')
with open('foo/usr/lib/my_arch/mesa/ld.so.conf', 'w') as f:
f.write('/mesa')

os.makedirs('foo/usr/lib/my_arch/mesa-egl/')
with open('foo/usr/lib/my_arch/mesa-egl/ld.so.conf', 'w') as f:
f.write('# Standalone comment\n')
f.write('/mesa-egl')

config = snapcraft.yaml.Config()
environment = config.runtime_env('foo')

# Ensure that the LD_LIBRARY_PATH includes all the above paths
paths = []
for variable in environment:
if 'LD_LIBRARY_PATH' in variable:
these_paths = variable.split('=')[1].strip()
paths.extend(these_paths.replace('"', '').split(':'))

self.assertTrue(len(paths) > 0,
'Expected LD_LIBRARY_PATH to be in environment')

for expected in ['foo/mesa', 'foo/mesa-egl']:
self.assertTrue(expected in paths,
'Expected LD_LIBRARY_PATH to include "{}"'.format(
expected))


class TestValidation(tests.TestCase):

def setUp(self):
Expand Down
10 changes: 10 additions & 0 deletions snapcraft/yaml.py
Expand Up @@ -26,6 +26,7 @@

from snapcraft import (
common,
libraries,
pluginhandler,
wiki,
)
Expand Down Expand Up @@ -205,13 +206,22 @@ def runtime_env(self, root):
'{0}/usr/bin',
'$PATH'
]).format(root) + '"')

# Add the default LD_LIBRARY_PATH
env.append('LD_LIBRARY_PATH="' + ':'.join([
'{0}/lib',
'{0}/usr/lib',
'{0}/lib/{1}',
'{0}/usr/lib/{1}',
'$LD_LIBRARY_PATH'
]).format(root, common.get_arch_triplet()) + '"')

# Add more specific LD_LIBRARY_PATH if necessary
ld_library_paths = libraries.determine_ld_library_path(root)
if ld_library_paths:
env.append('LD_LIBRARY_PATH="' + ':'.join(ld_library_paths) +
':$LD_LIBRARY_PATH"')

return env

def build_env(self, root):
Expand Down

0 comments on commit d0ab400

Please sign in to comment.