blob: b20479904d3bd27fd5183fd7089dc93175b33248 [file] [log] [blame]
# Copyright 2017 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import shutil
import stat
import unittest
from src.test.py.bazel import test_base
class CcImportTest(test_base.TestBase):
def createProjectFiles(self,
alwayslink=0,
system_provided=0,
linkstatic=1,
provide_header=True):
self.ScratchFile('WORKSPACE')
# We use the outputs of cc_binary and cc_library as precompiled
# libraries for cc_import
self.ScratchFile(
'lib/BUILD',
[
'package(default_visibility = ["//visibility:public"])',
'',
'cc_binary(',
' name = "libA.so",',
' srcs = ["a.cc"],',
' linkshared = 1,',
')',
'',
'filegroup(',
' name = "libA_ifso",',
' srcs = [":libA.so"],',
' output_group = "interface_library",',
')',
'',
'cc_library(',
' name = "libA",',
' srcs = ["a.cc", "a_al.cc"],',
')',
'',
'filegroup(',
' name = "libA_archive",',
' srcs = [":libA"],',
' output_group = "archive",',
')',
'',
'cc_import(',
' name = "A",',
' static_library = "//lib:libA_archive",',
' shared_library = "//lib:libA.so",'
if not system_provided else '',
# On Windows, we always need the interface library
' interface_library = "//lib:libA_ifso",'
if self.IsWindows() else (
# On Unix, we use .so file as interface library
# if system_provided is true
' interface_library = "//lib:libA.so",'
if system_provided else ''),
' hdrs = ["a.h"],' if provide_header else '',
' alwayslink = %s,' % str(alwayslink),
' system_provided = %s,' % str(system_provided),
')',
])
self.ScratchFile('lib/a.cc', [
'#include <stdio.h>',
'',
'#ifdef _WIN32',
' #define DLLEXPORT __declspec(dllexport)',
'#else',
' #define DLLEXPORT',
'#endif',
'',
'DLLEXPORT void HelloWorld() {',
' printf("HelloWorld\\n");',
'}',
])
# For testing alwayslink=1
self.ScratchFile('lib/a_al.cc', [
'extern int global_variable;',
'int init() {',
' ++global_variable;',
' return global_variable;',
'}',
'int x = init();',
'int y = init();',
])
self.ScratchFile('lib/a.h', [
'void HelloWorld();',
])
self.ScratchFile('main/BUILD', [
'cc_binary(',
' name = "B",',
' srcs = ["b.cc"],',
' deps = ["//lib:A",],',
' linkstatic = %s,' % str(linkstatic),
')',
])
self.ScratchFile('main/b.cc', [
'#include <stdio.h>',
'#include "lib/a.h"',
'int global_variable = 0;',
'int main() {',
' HelloWorld();',
' printf("global : %d\\n", global_variable);',
' return 0;',
'}',
])
def getBazelInfo(self, info_key):
exit_code, stdout, stderr = self.RunBazel(['info', info_key])
self.AssertExitCode(exit_code, 0, stderr)
return stdout[0]
def testLinkStaticLibrary(self):
self.createProjectFiles(alwayslink=0, linkstatic=1)
bazel_bin = self.getBazelInfo('bazel-bin')
suffix = '.exe' if self.IsWindows() else ''
exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
self.AssertExitCode(exit_code, 0, stderr)
b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
self.assertTrue(os.path.exists(b_bin))
exit_code, stdout, stderr = self.RunProgram([b_bin])
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'HelloWorld')
self.assertEqual(stdout[1], 'global : 0')
def testAlwayslinkStaticLibrary(self):
self.createProjectFiles(alwayslink=1, linkstatic=1)
bazel_bin = self.getBazelInfo('bazel-bin')
suffix = '.exe' if self.IsWindows() else ''
exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
self.AssertExitCode(exit_code, 0, stderr)
b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
self.assertTrue(os.path.exists(b_bin))
exit_code, stdout, stderr = self.RunProgram([b_bin])
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'HelloWorld')
self.assertEqual(stdout[1], 'global : 2')
def testLinkSharedLibrary(self):
self.createProjectFiles(linkstatic=0)
bazel_bin = self.getBazelInfo('bazel-bin')
suffix = '.exe' if self.IsWindows() else ''
exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
self.AssertExitCode(exit_code, 0, stderr)
b_bin = os.path.join(bazel_bin, 'main/B' + suffix)
self.assertTrue(os.path.exists(b_bin))
if self.IsWindows():
self.assertTrue(os.path.exists(os.path.join(bazel_bin, 'main/libA.so')))
exit_code, stdout, stderr = self.RunProgram([b_bin])
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'HelloWorld')
def testSystemProvidedSharedLibraryOnWinodws(self):
if not self.IsWindows():
return
self.createProjectFiles(system_provided=1, linkstatic=0)
bazel_bin = self.getBazelInfo('bazel-bin')
exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
self.AssertExitCode(exit_code, 0, stderr)
b_bin = os.path.join(bazel_bin, 'main/B.exe')
exit_code, stdout, stderr = self.RunProgram([b_bin])
# Should fail because missing libA.so
self.assertFalse(exit_code == 0)
# Let's build libA.so and add it into PATH
exit_code, stdout, stderr = self.RunBazel(['build', '//lib:libA.so'])
self.AssertExitCode(exit_code, 0, stderr)
exit_code, stdout, stderr = self.RunProgram(
[b_bin], env_add={
'PATH': str(os.path.join(bazel_bin, 'lib'))
})
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'HelloWorld')
def testSystemProvidedSharedLibraryOnUnix(self):
if not self.IsUnix():
return
self.createProjectFiles(system_provided=1, linkstatic=0)
bazel_bin = self.getBazelInfo('bazel-bin')
exit_code, _, stderr = self.RunBazel(['build', '//main:B'])
self.AssertExitCode(exit_code, 0, stderr)
b_bin = os.path.join(bazel_bin, 'main/B')
tmp_dir = self.ScratchDir('temp_dir_for_run_b_bin')
b_bin_tmp = os.path.join(tmp_dir, 'B')
# Copy the binary to a temp directory to make sure it cannot find
# libA.so
shutil.copyfile(b_bin, b_bin_tmp)
os.chmod(b_bin_tmp, stat.S_IRWXU)
exit_code, stdout, stderr = self.RunProgram([b_bin_tmp])
# Should fail because missing libA.so
self.assertFalse(exit_code == 0)
# Let's build libA.so and add it into PATH
exit_code, stdout, stderr = self.RunBazel(['build', '//lib:libA.so'])
self.AssertExitCode(exit_code, 0, stderr)
exit_code, stdout, stderr = self.RunProgram(
[b_bin_tmp], env_add={
# For Linux
'LD_LIBRARY_PATH': str(os.path.join(bazel_bin, 'lib')),
# For Mac
'DYLD_LIBRARY_PATH': str(os.path.join(bazel_bin, 'lib')),
})
self.AssertExitCode(exit_code, 0, stderr)
self.assertEqual(stdout[0], 'HelloWorld')
def testCcImportHeaderCheck(self):
self.createProjectFiles(provide_header=False)
# Build should fail, because lib/a.h is not declared in BUILD file, disable
# sandbox so that bazel produces same error across different platforms.
exit_code, _, stderr = self.RunBazel(
['build', '//main:B', '--spawn_strategy=standalone'])
self.AssertExitCode(exit_code, 1, stderr)
self.assertIn('this rule is missing dependency declarations for the'
' following files included by \'main/b.cc\':',
''.join(stderr))
def AssertFileContentContains(self, file_path, entry):
with open(file_path, 'r') as f:
if entry not in f.read():
self.fail('File "%s" does not contain "%s"' % (file_path, entry))
if __name__ == '__main__':
unittest.main()