Merge branch 'ClangCross' into 'master'

Better support for cross compilation with clang v2

See merge request ita1024/waf!2233
This commit is contained in:
ita1024 2019-05-10 05:50:55 +00:00
commit 89146d9030
7 changed files with 373 additions and 0 deletions

View File

@ -0,0 +1,14 @@
To cross compile for Windows in MSVC mode from Linux, you will require the following:
* A partition with Windows installed (NTFS).
* Visual Studio (Tested with 2017).
* The Windows SDK.
* lowntfs-3g file system driver.
Make sure the Windows partition is mounted with "-t lowntfs-3g -o defaults,ignore_case,windows_names".
This will allow Clang to find all headers and libraries referenced by scripts and headers, otherwise you will run into case sensitivity errors.
Clang uses the following environment variables to detect the Visual Studio install: VCINSTALLDIR, VCToolsInstallDir, INCLUDE, LIB, LIBPATH
I just copied these from the output of the "set" command in an MSVC command prompt on Windows and translated the paths to Linux paths.
Notice how the semicolon is still used as a path separator.
See "example_environment_linux.sh" for how my setup looks like.
It expects the Windows partition to be mounted on /mnt/windows, with VS2017 installed and Windows 10 SDK 10.0.17763.0.

View File

@ -0,0 +1,5 @@
export VCINSTALLDIR="/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/"
export VCToolsInstallDir="/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/"
export INCLUDE="/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/atlmfc/include;/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/include;/mnt/windows/program files (x86)/windows kits/10/include/10.0.17763.0/ucrt;/mnt/windows/program files (x86)/windows kits/10/include/10.0.17763.0/shared;/mnt/windows/program files (x86)/windows kits/10/include/10.0.17763.0/um;/mnt/windows/program files (x86)/windows kits/10/include/10.0.17763.0/winrt;/mnt/windows/program files (x86)/windows kits/10/include/10.0.17763.0/cppwinrt"
export LIB="/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/atlmfc/lib/x64;/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/lib/x64;/mnt/windows/program files (x86)/windows kits/10/lib/10.0.17763.0/ucrt/x64;/mnt/windows/program files (x86)/windows kits/10/lib/10.0.17763.0/um/x64"
export LIBPATH="/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/atlmfc/lib/x64;/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/lib/x64;/mnt/windows/program files (x86)/microsoft visual studio/2017/community/vc/tools/msvc/14.16.27023/lib/x86/store/references;/mnt/windows/program files (x86)/windows kits/10/unionmetadata/10.0.17763.0;/mnt/windows/program files (x86)/windows kits/10/references/10.0.17763.0"

View File

@ -0,0 +1,11 @@
#include <Windows.h>
int main(int argc, char* argv[])
{
(void)argc;
(void)argv;
WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), "Hello world!\n", 13, NULL, NULL);
return 0;
}

View File

@ -0,0 +1,32 @@
#! /usr/bin/env python
# encoding: utf-8
# DragoonX6 2019
# the following two variables are used by the target "waf dist"
VERSION='0.0.1'
APPNAME='hello_msvc'
top = '.'
from waflib.Configure import conf, ConfigurationContext
from waflib.Options import OptionsContext
def options(opt):
opt.load('clang_cross')
def configure(conf):
conf.load('clang_cross')
if not conf.env.implib_PATTERN == '%s.lib':
conf.fatal('''clang is not configured to compile in msvc mode.
Use flag '--clang-target-triple=x86_64-windows-msvc' to configure.
On Windows you're likely to require running from an MSVC command prompt.
On Linux you will need to have access to a Windows partition with VS installed, and the environment set up properly.
See the ReadMe for more information.''')
conf.env.append_value('CFLAGS', conf.env.CFLAGS_CRT_MULTITHREADED_DLL)
def build(bld):
bld.program(
source = 'hello.c',
target = 'hello_msvc')

View File

@ -0,0 +1,92 @@
#!/usr/bin/env python
# encoding: utf-8
# Krzysztof Kosiński 2014
# DragoonX6 2018
"""
Detect the Clang C compiler
This version is an attempt at supporting the -target and -sysroot flag of Clang.
"""
from waflib.Tools import ccroot, ar, gcc
from waflib.Configure import conf
import waflib.Context
import waflib.extras.clang_cross_common
def options(opt):
"""
Target triplet for clang::
$ waf configure --clang-target-triple=x86_64-pc-linux-gnu
"""
cc_compiler_opts = opt.add_option_group('Configuration options')
cc_compiler_opts.add_option('--clang-target-triple', default=None,
help='Target triple for clang',
dest='clang_target_triple')
cc_compiler_opts.add_option('--clang-sysroot', default=None,
help='Sysroot for clang',
dest='clang_sysroot')
@conf
def find_clang(conf):
"""
Finds the program clang and executes it to ensure it really is clang
"""
import os
cc = conf.find_program('clang', var='CC')
if conf.options.clang_target_triple != None:
conf.env.append_value('CC', ['-target', conf.options.clang_target_triple])
if conf.options.clang_sysroot != None:
sysroot = str()
if os.path.isabs(conf.options.clang_sysroot):
sysroot = conf.options.clang_sysroot
else:
sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clang_sysroot))
conf.env.append_value('CC', ['--sysroot', sysroot])
conf.get_cc_version(cc, clang=True)
conf.env.CC_NAME = 'clang'
@conf
def clang_modifier_x86_64_w64_mingw32(conf):
conf.gcc_modifier_win32()
@conf
def clang_modifier_i386_w64_mingw32(conf):
conf.gcc_modifier_win32()
@conf
def clang_modifier_x86_64_windows_msvc(conf):
conf.clang_modifier_msvc()
# Allow the user to override any flags if they so desire.
clang_modifier_user_func = getattr(conf, 'clang_modifier_x86_64_windows_msvc_user', None)
if clang_modifier_user_func:
clang_modifier_user_func()
@conf
def clang_modifier_i386_windows_msvc(conf):
conf.clang_modifier_msvc()
# Allow the user to override any flags if they so desire.
clang_modifier_user_func = getattr(conf, 'clang_modifier_i386_windows_msvc_user', None)
if clang_modifier_user_func:
clang_modifier_user_func()
def configure(conf):
conf.find_clang()
conf.find_program(['llvm-ar', 'ar'], var='AR')
conf.find_ar()
conf.gcc_common_flags()
# Allow the user to provide flags for the target platform.
conf.gcc_modifier_platform()
# And allow more fine grained control based on the compiler's triplet.
conf.clang_modifier_target_triple()
conf.cc_load_tools()
conf.cc_add_flags()
conf.link_add_flags()

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python
# encoding: utf-8
# DragoonX6 2018
"""
Common routines for cross_clang.py and cross_clangxx.py
"""
from waflib.Configure import conf
import waflib.Context
def normalize_target_triple(target_triple):
target_triple = target_triple[:-1]
normalized_triple = target_triple.replace('--', '-unknown-')
if normalized_triple.startswith('-'):
normalized_triple = 'unknown' + normalized_triple
if normalized_triple.endswith('-'):
normalized_triple += 'unknown'
# Normalize MinGW builds to *arch*-w64-mingw32
if normalized_triple.endswith('windows-gnu'):
normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-w64-mingw32'
# Strip the vendor when doing msvc builds, since it's unused anyway.
if normalized_triple.endswith('windows-msvc'):
normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-windows-msvc'
return normalized_triple.replace('-', '_')
@conf
def clang_modifier_msvc(conf):
import os
"""
Really basic setup to use clang in msvc mode.
We actually don't really want to do a lot, even though clang is msvc compatible
in this mode, that doesn't mean we're actually using msvc.
It's probably the best to leave it to the user, we can assume msvc mode if the user
uses the clang-cl frontend, but this module only concerns itself with the gcc-like frontend.
"""
v = conf.env
v.cprogram_PATTERN = '%s.exe'
v.cshlib_PATTERN = '%s.dll'
v.implib_PATTERN = '%s.lib'
v.IMPLIB_ST = '-Wl,-IMPLIB:%s'
v.SHLIB_MARKER = []
v.CFLAGS_cshlib = []
v.LINKFLAGS_cshlib = ['-Wl,-DLL']
v.cstlib_PATTERN = '%s.lib'
v.STLIB_MARKER = []
del(v.AR)
conf.find_program(['llvm-lib', 'lib'], var='AR')
v.ARFLAGS = ['-nologo']
v.AR_TGT_F = ['-out:']
# Default to the linker supplied with llvm instead of link.exe or ld
v.LINK_CC = v.CC + ['-fuse-ld=lld', '-nostdlib']
v.CCLNK_TGT_F = ['-o']
v.def_PATTERN = '-Wl,-def:%s'
v.LINKFLAGS = []
v.LIB_ST = '-l%s'
v.LIBPATH_ST = '-Wl,-LIBPATH:%s'
v.STLIB_ST = '-l%s'
v.STLIBPATH_ST = '-Wl,-LIBPATH:%s'
CFLAGS_CRT_COMMON = [
'-Xclang', '--dependent-lib=oldnames',
'-Xclang', '-fno-rtti-data',
'-D_MT'
]
v.CFLAGS_CRT_MULTITHREADED = CFLAGS_CRT_COMMON + [
'-Xclang', '-flto-visibility-public-std',
'-Xclang', '--dependent-lib=libcmt',
]
v.CXXFLAGS_CRT_MULTITHREADED = v.CFLAGS_CRT_MULTITHREADED
v.CFLAGS_CRT_MULTITHREADED_DBG = CFLAGS_CRT_COMMON + [
'-D_DEBUG',
'-Xclang', '-flto-visibility-public-std',
'-Xclang', '--dependent-lib=libcmtd',
]
v.CXXFLAGS_CRT_MULTITHREADED_DBG = v.CFLAGS_CRT_MULTITHREADED_DBG
v.CFLAGS_CRT_MULTITHREADED_DLL = CFLAGS_CRT_COMMON + [
'-D_DLL',
'-Xclang', '--dependent-lib=msvcrt'
]
v.CXXFLAGS_CRT_MULTITHREADED_DLL = v.CFLAGS_CRT_MULTITHREADED_DLL
v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = CFLAGS_CRT_COMMON + [
'-D_DLL',
'-D_DEBUG',
'-Xclang', '--dependent-lib=msvcrtd',
]
v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CFLAGS_CRT_MULTITHREADED_DLL_DBG
@conf
def clang_modifier_target_triple(conf, cpp=False):
compiler = conf.env.CXX if cpp else conf.env.CC
output = conf.cmd_and_log(compiler + ['-dumpmachine'], output=waflib.Context.STDOUT)
modifier = ('clangxx' if cpp else 'clang') + '_modifier_'
clang_modifier_func = getattr(conf, modifier + normalize_target_triple(output), None)
if clang_modifier_func:
clang_modifier_func()

View File

@ -0,0 +1,106 @@
#!/usr/bin/env python
# encoding: utf-8
# Thomas Nagy 2009-2018 (ita)
# DragoonX6 2018
"""
Detect the Clang++ C++ compiler
This version is an attempt at supporting the -target and -sysroot flag of Clang++.
"""
from waflib.Tools import ccroot, ar, gxx
from waflib.Configure import conf
import waflib.extras.clang_cross_common
def options(opt):
"""
Target triplet for clang++::
$ waf configure --clangxx-target-triple=x86_64-pc-linux-gnu
"""
cxx_compiler_opts = opt.add_option_group('Configuration options')
cxx_compiler_opts.add_option('--clangxx-target-triple', default=None,
help='Target triple for clang++',
dest='clangxx_target_triple')
cxx_compiler_opts.add_option('--clangxx-sysroot', default=None,
help='Sysroot for clang++',
dest='clangxx_sysroot')
@conf
def find_clangxx(conf):
"""
Finds the program clang++, and executes it to ensure it really is clang++
"""
import os
cxx = conf.find_program('clang++', var='CXX')
if conf.options.clangxx_target_triple != None:
conf.env.append_value('CXX', ['-target', conf.options.clangxx_target_triple])
if conf.options.clangxx_sysroot != None:
sysroot = str()
if os.path.isabs(conf.options.clangxx_sysroot):
sysroot = conf.options.clangxx_sysroot
else:
sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clangxx_sysroot))
conf.env.append_value('CXX', ['--sysroot', sysroot])
conf.get_cc_version(cxx, clang=True)
conf.env.CXX_NAME = 'clang'
@conf
def clangxx_modifier_x86_64_w64_mingw32(conf):
conf.gcc_modifier_win32()
@conf
def clangxx_modifier_i386_w64_mingw32(conf):
conf.gcc_modifier_win32()
@conf
def clangxx_modifier_msvc(conf):
v = conf.env
v.cxxprogram_PATTERN = v.cprogram_PATTERN
v.cxxshlib_PATTERN = v.cshlib_PATTERN
v.CXXFLAGS_cxxshlib = []
v.LINKFLAGS_cxxshlib = v.LINKFLAGS_cshlib
v.cxxstlib_PATTERN = v.cstlib_PATTERN
v.LINK_CXX = v.CXX + ['-fuse-ld=lld', '-nostdlib']
v.CXXLNK_TGT_F = v.CCLNK_TGT_F
@conf
def clangxx_modifier_x86_64_windows_msvc(conf):
conf.clang_modifier_msvc()
conf.clangxx_modifier_msvc()
# Allow the user to override any flags if they so desire.
clang_modifier_user_func = getattr(conf, 'clangxx_modifier_x86_64_windows_msvc_user', None)
if clang_modifier_user_func:
clang_modifier_user_func()
@conf
def clangxx_modifier_i386_windows_msvc(conf):
conf.clang_modifier_msvc()
conf.clangxx_modifier_msvc()
# Allow the user to override any flags if they so desire.
clang_modifier_user_func = getattr(conf, 'clangxx_modifier_i386_windows_msvc_user', None)
if clang_modifier_user_func:
clang_modifier_user_func()
def configure(conf):
conf.find_clangxx()
conf.find_program(['llvm-ar', 'ar'], var='AR')
conf.find_ar()
conf.gxx_common_flags()
# Allow the user to provide flags for the target platform.
conf.gxx_modifier_platform()
# And allow more fine grained control based on the compiler's triplet.
conf.clang_modifier_target_triple(cpp=True)
conf.cxx_load_tools()
conf.cxx_add_flags()
conf.link_add_flags()