Building world with clang

Dimitry Andric dimitry at andric.com
Tue Aug 17 11:32:33 UTC 2010


Hi,

Since clang has gone into the tree, there has been an effort to get head
in a state where world can optionally be built with it.  A number of
changes required for this have already been committed, mainly thanks to
Ed Schouten, Roman Divacky and Rui Paulo.  Most of these changes were
adapted from the clangbsd project branch.

There are several other changes in the queue, pending review and/or
further enhancement, but I would like to solicit your comments about one
particular set: the changes required to let buildworld use clang as the
compiler.

Probably the most logical way to specify that you want world built with
clang, is to put CC=clang and CXX=clang++ in /etc/src.conf.  Any
necessary modifications to Makefile.inc1 or bsd.*.mk can then be put
between conditionals like:

.if ${CC:T:Mclang} == "clang"
[...stuff specific to clang...]
.endif

so nothing will change for non-clang builds.

Now, for building clang as the bootstrap compiler, there are basically
two methods to make it use the correct headers, C startup objects, and
libraries from the object tree (${WORLDTMP}):

1) The "isysroot" method: build a regular version of clang, and make
   sure WMAKEENV contains something like:

   CC="${CC} -isysroot ${WORLDTMP} -B${WORLDTMP}/usr/lib/ \
                                   -L${WORLDTMP}/usr/lib/"

2) The "tools-prefix" method: build a special version of clang, that
   has its default search paths for headers, startup objects and
   libraries modified, to look for everything under ${WORLDTMP}.

Method 1) is used in the clangbsd project branch.

Method 2) is similar to what is used for building the in-tree gcc as
the bootstrap compiler.  During the cross-tools stage, TOOLS_PREFIX is
defined to point at ${WORLDTMP}, and the bootstrap gcc's built-in
search paths get prefixed with it.

An advantage of method 1) is that it does not require any modifications
to the compiler, and basically just a few extra command line arguments.
The same method could probably even be made to work for gcc.

However, a disadvantage is that the built-in search paths of the
bootstrap compiler are not entirely disabled by using the -isysroot, -B
and -L flags, so there is still a chance that headers, objects or
libraries outside of ${WORLDTMP} will be picked up during the world
stage.

An advantage of method 2) is that you can be 100% sure all built-in
search paths of the bootstrap compiler point to directories under
${WORLDTMP}.  Of course, a disadvantage is that you have to make some
modifications to the compiler source itself.

I would like to hear your opinions about which method is preferred, or
if there may be another good way to solve the bootstrap compiler issue.

I have also attached two patches to this mail, which can be applied to
head, to show the exact set of changes required for each method.

-------------- next part --------------
The "isysroot" method for building world with clang.

First of all, Makefile.inc1 is modified to build the clang libraries and
binaries during the cross-tools stage, iff CC=clang.

We basically adjust WMAKEENV, which applies to the world stage, and
LIB32FLAGS, which optionally applies to 32-bit world stage, to add
-isysroot, -B and -L options, so the compiler looks under ${WORLDTMP}
for its headers, startup objects and libraries.

We also need to create symlinks from ${WORLDTMP}/usr/bin/as and ld to
${WORLDTMP}/usr/lib, since the -B option in clang is not additive, and
is used both for finding CRT startup objects and for finding the
assembler and linker.


diff --git a/Makefile.inc1 b/Makefile.inc1
index d2581c5..c31eba9 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -257,6 +257,10 @@ WMAKEENV=	${CROSSENV} \
 		VERSION="${VERSION}" \
 		INSTALL="sh ${.CURDIR}/tools/install.sh" \
 		PATH=${TMPPATH}
+.if ${CC:T:Mclang} == "clang"
+WMAKEENV+=	CC="${CC} -isysroot ${WORLDTMP} -B${WORLDTMP}/usr/lib/ -L${WORLDTMP}/usr/lib/" \
+		CXX="${CXX} -isysroot ${WORLDTMP} -B${WORLDTMP}/usr/lib/ -L${WORLDTMP}/usr/lib/"
+.endif
 .if ${MK_CDDL} == "no"
 WMAKEENV+=	NO_CTF=1
 .endif
@@ -289,8 +293,11 @@ LIB32WMAKEENV=	MACHINE=powerpc MACHINE_ARCH=powerpc \
 .endif
 
 
-LIB32FLAGS=	-m32 ${LIB32CPUFLAGS} -DCOMPAT_32BIT \
-		-isystem ${LIB32TMP}/usr/include/ \
+LIB32FLAGS=	-m32 ${LIB32CPUFLAGS} -DCOMPAT_32BIT
+.if ${CC:T:Mclang} == "clang"
+LIB32FLAGS+=	-isysroot ${LIB32TMP}/
+.endif
+LIB32FLAGS+=	-isystem ${LIB32TMP}/usr/include/ \
 		-L${LIB32TMP}/usr/lib32 \
 		-B${LIB32TMP}/usr/lib32
 
@@ -440,6 +447,11 @@ everything:
 	@echo "--------------------------------------------------------------"
 	@echo ">>> stage 4.4: building everything"
 	@echo "--------------------------------------------------------------"
+.if ${CC:T:Mclang} == "clang"
+	# mergemaster goes through this but those files do not exist
+	[ ! -e ${WORLDTMP}/usr/bin/as ] || ln -sf ${WORLDTMP}/usr/bin/as ${WORLDTMP}/usr/lib/as
+	[ ! -e ${WORLDTMP}/usr/bin/ld ] || ln -sf ${WORLDTMP}/usr/bin/ld ${WORLDTMP}/usr/lib/ld
+.endif
 	${_+_}cd ${.CURDIR}; ${WMAKE} par-all
 .if defined(LIB32TMP)
 build32:
@@ -453,6 +465,12 @@ build32:
 	mtree -deU -f ${.CURDIR}/etc/mtree/BSD.include.dist \
 	    -p ${LIB32TMP}/usr/include >/dev/null
 	mkdir -p ${WORLDTMP}
+.if ${CC:T:Mclang} == "clang"
+	# relink /usr/bin/{as,ld} to the lib32 tmp so the -B can pick up
+	# the /usr/bin/ld and /usr/bin/as
+	ln -sf ${WORLDTMP}/usr/bin/as ${LIB32TMP}/usr/lib32/as
+	ln -sf ${WORLDTMP}/usr/bin/ld ${LIB32TMP}/usr/lib32/ld
+.endif
 	ln -sf ${.CURDIR}/sys ${WORLDTMP}
 .if ${MK_KERBEROS} != "no"
 .for _t in obj depend all
@@ -1078,8 +1096,15 @@ _kgzip=		usr.sbin/kgzip
 .endif
 .endif
 
+.if ${CC:T:Mclang} == "clang"
+_clang=		usr.bin/clang
+_clang_libs=	lib/clang
+.endif
+
 cross-tools:
 .for _tool in \
+    ${_clang_libs} \
+    ${_clang} \
     gnu/usr.bin/binutils \
     gnu/usr.bin/cc \
     usr.bin/xlint/lint1 usr.bin/xlint/lint2 usr.bin/xlint/xlint \

-------------- next part --------------
The "tools-prefix" method for building world with clang.

First of all, Makefile.inc1 is modified to build the clang libraries and
binaries during the cross-tools stage, iff CC=clang.

The lib/clang/clang.build.mk file, which contains common build settings
for all llvm and clang sources, is modified to add a CLANG_PREFIX macro
to CFLAGS, iff TOOLS_PREFIX is defined.

In the clang sources, the files that define the built-in search paths
for headers, startup objects and libraries, are modified to use the
(optional) CLANG_PREFIX macro as prefix for all those paths.


diff --git a/Makefile.inc1 b/Makefile.inc1
index d2581c5..6e58396 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -1078,8 +1078,15 @@ _kgzip=		usr.sbin/kgzip
 .endif
 .endif
 
+.if ${CC:T:Mclang} == "clang"
+_clang=		usr.bin/clang
+_clang_libs=	lib/clang
+.endif
+
 cross-tools:
 .for _tool in \
+    ${_clang_libs} \
+    ${_clang} \
     gnu/usr.bin/binutils \
     gnu/usr.bin/cc \
     usr.bin/xlint/lint1 usr.bin/xlint/lint2 usr.bin/xlint/xlint \
diff --git a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
index a78d153..3506590 100644
--- a/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
+++ b/contrib/llvm/tools/clang/lib/Driver/ToolChains.cpp
@@ -26,6 +26,10 @@
 
 #include <cstdlib> // ::getenv
 
+#ifndef CLANG_PREFIX
+#define CLANG_PREFIX
+#endif
+
 using namespace clang::driver;
 using namespace clang::driver::toolchains;
 
@@ -869,11 +873,9 @@ FreeBSD::FreeBSD(const HostInfo &Host, const llvm::Triple& Triple, bool Lib32)
   getProgramPaths().push_back(getDriver().Dir + "/../libexec");
   getProgramPaths().push_back("/usr/libexec");
   if (Lib32) {
-    getFilePaths().push_back(getDriver().Dir + "/../lib32");
-    getFilePaths().push_back("/usr/lib32");
+    getFilePaths().push_back(CLANG_PREFIX "/usr/lib32");
   } else {
-    getFilePaths().push_back(getDriver().Dir + "/../lib");
-    getFilePaths().push_back("/usr/lib");
+    getFilePaths().push_back(CLANG_PREFIX "/usr/lib");
   }
 }
 
diff --git a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
index fcfee71..9187148 100644
--- a/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/contrib/llvm/tools/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -30,6 +30,9 @@
   #define WIN32_LEAN_AND_MEAN 1
   #include <windows.h>
 #endif
+#ifndef CLANG_PREFIX
+#define CLANG_PREFIX
+#endif
 using namespace clang;
 using namespace clang::frontend;
 
@@ -408,9 +411,10 @@ static bool getWindowsSDKDir(std::string &path) {
 
 void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
                                             const HeaderSearchOptions &HSOpts) {
-#if 0 /* Remove unneeded include paths. */
   // FIXME: temporary hack: hard-coded paths.
-  AddPath("/usr/local/include", System, true, false, false);
+#ifndef __FreeBSD__
+  AddPath(CLANG_PREFIX "/usr/local/include", System, true, false, false);
+#endif
 
   // Builtin includes use #include_next directives and should be positioned
   // just prior C include dirs.
@@ -421,7 +425,6 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
     P.appendComponent("include");
     AddPath(P.str(), System, false, false, false, /*IgnoreSysRoot=*/ true);
   }
-#endif
 
   // Add dirs specified via 'configure --with-c-include-dirs'.
   llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
@@ -518,13 +521,15 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
   case llvm::Triple::MinGW32:
     AddPath("c:/mingw/include", System, true, false, false);
     break;
+  case llvm::Triple::FreeBSD:
+    AddPath(CLANG_PREFIX "/usr/include/clang/" CLANG_VERSION_STRING,
+      System, false, false, false);
+    break;
   default:
     break;
   }
 
-  AddPath("/usr/include/clang/" CLANG_VERSION_STRING,
-    System, false, false, false);
-  AddPath("/usr/include", System, false, false, false);
+  AddPath(CLANG_PREFIX "/usr/include", System, false, false, false);
 }
 
 void InitHeaderSearch::
@@ -726,8 +731,10 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple) {
   case llvm::Triple::FreeBSD:
     // FreeBSD 8.0
     // FreeBSD 7.3
-    AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2", "", "", "", triple);
-    AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2/backward", "", "", "", triple);
+    AddGnuCPlusPlusIncludePaths(CLANG_PREFIX "/usr/include/c++/4.2",
+                                "", "", "", triple);
+    AddGnuCPlusPlusIncludePaths(CLANG_PREFIX "/usr/include/c++/4.2/backward",
+                                "", "", "", triple);
     break;
   case llvm::Triple::Minix:
     AddGnuCPlusPlusIncludePaths("/usr/gnu/include/c++/4.4.3",
diff --git a/lib/clang/clang.build.mk b/lib/clang/clang.build.mk
index 6351eda..86384db 100644
--- a/lib/clang/clang.build.mk
+++ b/lib/clang/clang.build.mk
@@ -28,6 +28,10 @@ LLVM_REQUIRES_RTTI=
 CFLAGS+=-fno-rtti
 .endif
 
+.ifdef TOOLS_PREFIX
+CFLAGS+=-DCLANG_PREFIX=\"${TOOLS_PREFIX}\"
+.endif
+
 .PATH:	${LLVM_SRCS}/${SRCDIR}
 
 TBLGEN=tblgen ${CFLAGS:M-I*}



More information about the freebsd-current mailing list