Date: prev next · Thread: first prev next last
2012 Archives by date, by thread · List index



 Hello,

 attached is my implementation of basic build support for using Clang compiler 
plugin during building LO. I'm posting it here first in case our build system 
people have different ideas to how I have integrated it in the build system, 
if there are no comments, I will push it.

-- 
 Lubos Lunak
 l.lunak@suse.cz
From 6c63f9809ecaa63e2db6fb606b573ab12f09752f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lubo=C5=A1=20Lu=C5=88=C3=A1k?= <l.lunak@suse.cz>
Date: Fri, 5 Oct 2012 18:17:13 +0200
Subject: [PATCH] initial support for clang compiler plugins

The plugin is intentionally built using a custom Makefile,
because it's used by gbuild, so I don't want to build the plugin
using gbuild too. It is also intentionally not placed under workdir/,
as that is cleaned by 'make clean', the plugin is cleaned only
by 'make distclean', so that cleaning it doesn't cause ccache misses.
Right now there's a relatively trivial plugin that just checks
for unused rtl::OUString variables.

Change-Id: Ic05eba8d6260eec123c9e699eb5385abfe1b832f
---
 Makefile.top                                  |    6 ++-
 compilerplugins/.gitignore                    |    1 +
 compilerplugins/Makefile                      |   23 +++++++++
 compilerplugins/Makefile-clang.mk             |   47 +++++++++++++++++
 compilerplugins/Makefile.mk                   |   29 +++++++++++
 compilerplugins/clang/compileplugin.cxx       |   66 ++++++++++++++++++++++++
 compilerplugins/clang/compileplugin.hxx       |   14 ++++++
 compilerplugins/clang/unusedvariablecheck.cxx |   67 +++++++++++++++++++++++++
 compilerplugins/clang/unusedvariablecheck.hxx |   36 +++++++++++++
 config_host.mk.in                             |    1 +
 configure.in                                  |   39 ++++++++++++++
 solenv/gbuild/platform/com_GCC_class.mk       |    2 +
 solenv/gbuild/platform/com_GCC_defs.mk        |    6 +++
 13 files changed, 335 insertions(+), 2 deletions(-)
 create mode 100644 compilerplugins/.gitignore
 create mode 100644 compilerplugins/Makefile
 create mode 100644 compilerplugins/Makefile-clang.mk
 create mode 100644 compilerplugins/Makefile.mk
 create mode 100644 compilerplugins/clang/compileplugin.cxx
 create mode 100644 compilerplugins/clang/compileplugin.hxx
 create mode 100644 compilerplugins/clang/unusedvariablecheck.cxx
 create mode 100644 compilerplugins/clang/unusedvariablecheck.hxx

diff --git a/Makefile.top b/Makefile.top
index bb632a2..bd85703 100644
--- a/Makefile.top
+++ b/Makefile.top
@@ -350,10 +350,12 @@ ifeq ($(CROSS_COMPILING),YES)
        rm -rf $(SRCDIR)/*/$(INPATH_FOR_BUILD)
 endif
 
+include $(SRCDIR)/compilerplugins/Makefile.mk
+
 #
 # Distclean
 #
-distclean : clean
+distclean : clean compilerplugins-clean
 ifeq ($(BUILD_DMAKE),YES)
        (if [ -f dmake/Makefile ] ; then $(GNUMAKE) -j $(GMAKE_PARALLELISM) -C dmake distclean; fi) 
&& \
        rm -f solenv/*/bin/dmake*
@@ -391,7 +393,7 @@ endif
 #
 bootstrap: $(WORKDIR)/bootstrap
 
-$(WORKDIR)/bootstrap: solenv/bin/concat-deps.c
+$(WORKDIR)/bootstrap: solenv/bin/concat-deps.c compilerplugins
        @cd $(SRCDIR) && ./bootstrap
        @mkdir -p $(dir $@) && touch $@
 
diff --git a/compilerplugins/.gitignore b/compilerplugins/.gitignore
new file mode 100644
index 0000000..b672fde
--- /dev/null
+++ b/compilerplugins/.gitignore
@@ -0,0 +1 @@
+obj
diff --git a/compilerplugins/Makefile b/compilerplugins/Makefile
new file mode 100644
index 0000000..4281c12
--- /dev/null
+++ b/compilerplugins/Makefile
@@ -0,0 +1,23 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+ifeq ($(SOLARENV),)
+ifeq ($(gb_Side),)
+gb_Side:=host
+endif
+include $(dir $(realpath $(lastword $(MAKEFILE_LIST))))../config_$(gb_Side).mk
+endif
+
+include $(SRCDIR)/compilerplugins/Makefile.mk
+
+all: build
+build: compilerplugins
+clean: compilerplugins-clean
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/Makefile-clang.mk b/compilerplugins/Makefile-clang.mk
new file mode 100644
index 0000000..9c93931
--- /dev/null
+++ b/compilerplugins/Makefile-clang.mk
@@ -0,0 +1,47 @@
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+# Make sure variables in this Makefile do not conflict with other variables (e.g. from gbuild).
+
+CLANGSRC=compileplugin.cxx unusedvariablecheck.cxx
+
+CLANGDIR=/usr
+CLANGBUILD=/usr
+CLANGDEFS=-D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -fno-rtti
+CLANGINCLUDES=-I$(CLANGDIR)/include -I$(CLANGDIR)/tools/clang/include -I$(CLANGBUILD)/include 
-I$(CLANGBUILD)/tools/clang/include 
+CLANGCXXFLAGS=-O2 -Wall -g
+
+CLANGINDIR=$(SRCDIR)/compilerplugins/clang
+# Cannot use $(WORKDIR), the plugin should survive even 'make clean', otherwise the rebuilt
+# plugin will cause cache misses with ccache.
+CLANGOUTDIR=$(SRCDIR)/compilerplugins/obj
+
+compilerplugins: $(CLANGOUTDIR) $(CLANGOUTDIR)/compileplugin.so
+
+compilerplugins-clean:
+       rm -rf $(CLANGOUTDIR)
+
+$(CLANGOUTDIR):
+       mkdir -p $(CLANGOUTDIR)
+
+CLANGOBJS=
+
+define clangbuildsrc
+$(2): $(1) $(SRCDIR)/compilerplugins/Makefile-clang.mk
+       $(CXX) $(CLANGCXXFLAGS) $(CLANGDEFS) $(CLANGINCLUDES) $(1) -fPIC -c -o $(2)
+
+$(CLANGOUTDIR)/compileplugin.so: $(2)
+$(CLANGOUTDIR)/compileplugin.so: CLANGOBJS += $(2)
+endef
+
+$(foreach src, $(CLANGSRC), $(eval $(call clangbuildsrc, $(CLANGINDIR)/$(src), 
$(CLANGOUTDIR)/$(src:.cxx=.o))))
+
+$(CLANGOUTDIR)/compileplugin.so: $(CLANGOBJS)
+       $(CXX) -shared $(CLANGOBJS) -o $@
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/Makefile.mk b/compilerplugins/Makefile.mk
new file mode 100644
index 0000000..91a5daa
--- /dev/null
+++ b/compilerplugins/Makefile.mk
@@ -0,0 +1,29 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+.PHONY: compilerplugins compilerplugins-clean
+
+ifeq ($(COMPILER_PLUGINS),)
+
+# no support
+
+compilerplugins:
+compilerplugins-clean:
+
+else
+
+ifeq ($(COM_GCC_IS_CLANG),TRUE)
+
+include $(SRCDIR)/compilerplugins/Makefile-clang.mk
+
+endif
+
+endif
+
+# vim: set noet sw=4 ts=4:
diff --git a/compilerplugins/clang/compileplugin.cxx b/compilerplugins/clang/compileplugin.cxx
new file mode 100644
index 0000000..3b3a0cd
--- /dev/null
+++ b/compilerplugins/clang/compileplugin.cxx
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Based on LLVM/Clang.
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ */
+
+#include "compileplugin.hxx"
+
+#include <clang/AST/ASTConsumer.h>
+#include <clang/Frontend/CompilerInstance.h>
+#include <clang/Frontend/FrontendAction.h>
+#include <clang/Frontend/FrontendPluginRegistry.h>
+#include <clang/Rewrite/Rewriter.h>
+
+#include "unusedvariablecheck.hxx"
+
+using namespace clang;
+
+namespace loplugin
+{
+
+class AstConsumer
+    : public ASTConsumer
+    {
+    public:
+        explicit AstConsumer( ASTContext& context )
+            : rewriter( context.getSourceManager(), context.getLangOpts())
+            , unusedVariableCheck( context )
+            {
+            }
+        virtual void HandleTranslationUnit( ASTContext& context )
+            {
+            if( context.getDiagnostics().hasErrorOccurred())
+                return;
+            unusedVariableCheck.run();
+            // TODO also LO header files? or a subdir?
+           if( const RewriteBuffer* buf = rewriter.getRewriteBufferFor( 
context.getSourceManager().getMainFileID()))
+                buf->write( llvm::outs());
+            // TODO else write out the original file?
+            }
+    private:
+        Rewriter rewriter;
+        UnusedVariableCheck unusedVariableCheck;
+    };
+
+class LibreOfficeAction
+    : public PluginASTAction
+    {
+    public:
+        virtual ASTConsumer* CreateASTConsumer( CompilerInstance& Compiler, StringRef InFile )
+            {
+            return new AstConsumer( Compiler.getASTContext());
+            }
+        virtual bool ParseArgs( const CompilerInstance& CI, const std::vector< std::string >& args 
)
+            {
+            return true;
+            }
+    };
+
+} // namespace
+
+static FrontendPluginRegistry::Add< loplugin::LibreOfficeAction > X( "loplugin", "LibreOffice 
compile check plugin" );
diff --git a/compilerplugins/clang/compileplugin.hxx b/compilerplugins/clang/compileplugin.hxx
new file mode 100644
index 0000000..30fe24b
--- /dev/null
+++ b/compilerplugins/clang/compileplugin.hxx
@@ -0,0 +1,14 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Based on LLVM/Clang.
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ */
+
+#ifndef COMPILEPLUGIN_H
+#define COMPILEPLUGIN_H
+
+#endif // LOPLUGIN_H
diff --git a/compilerplugins/clang/unusedvariablecheck.cxx 
b/compilerplugins/clang/unusedvariablecheck.cxx
new file mode 100644
index 0000000..960eb44
--- /dev/null
+++ b/compilerplugins/clang/unusedvariablecheck.cxx
@@ -0,0 +1,67 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Based on LLVM/Clang.
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ */
+
+#include "unusedvariablecheck.hxx"
+
+#include <clang/Basic/SourceManager.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+UnusedVariableCheck::UnusedVariableCheck( ASTContext& context )
+    : context( context )
+    {
+    }
+
+void UnusedVariableCheck::run()
+    {
+    TraverseDecl( context.getTranslationUnitDecl());
+    }
+
+bool UnusedVariableCheck::VisitNamedDecl( NamedDecl* declaration )
+    {
+    // TODO also LO header files? or a subdir?
+    if( !context.getSourceManager().isFromMainFile( declaration->getLocStart()))
+        return true;
+    if( !isa< VarDecl >( declaration ))
+        return true;
+    const VarDecl* var = cast< VarDecl >( declaration );
+    if( var->isReferenced() || var->isUsed())
+        return true;
+    if( CXXRecordDecl* type = var->getType()->getAsCXXRecordDecl())
+        if( type->getQualifiedNameAsString() == "rtl::OUString" )
+            {
+            DiagnosticsEngine& diag = context.getDiagnostics();
+            // TODO WaE ?
+            unsigned diagid;
+            if( const ParmVarDecl* param = dyn_cast< ParmVarDecl >( var ))
+                {
+                // If this declaration does not have a body, then the parameter is indeed not used,
+                // so ignore.
+                if( const FunctionDecl* func = dyn_cast< FunctionDecl >( 
param->getParentFunctionOrMethod()))
+                    if( !func->doesThisDeclarationHaveABody())
+                        return true;
+                diagid = diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                "unused parameter %0 [loplugin]" );
+                diag.Report( param->getLocStart(), diagid ) << param->getDeclName();
+                }
+            else
+                {
+                diagid = diag.getCustomDiagID( DiagnosticsEngine::Warning,
+                "unused variable %0 [loplugin]" );
+                diag.Report( var->getLocStart(), diagid ) << var->getDeclName();
+                }
+            }
+    return true;
+    }
+
+} // namespace
diff --git a/compilerplugins/clang/unusedvariablecheck.hxx 
b/compilerplugins/clang/unusedvariablecheck.hxx
new file mode 100644
index 0000000..81b3acc
--- /dev/null
+++ b/compilerplugins/clang/unusedvariablecheck.hxx
@@ -0,0 +1,36 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * Based on LLVM/Clang.
+ *
+ * This file is distributed under the University of Illinois Open Source
+ * License. See LICENSE.TXT for details.
+ *
+ */
+
+#ifndef UNUSEDVARIABLECHECK_H
+#define UNUSEDVARIABLECHECK_H
+
+#include <clang/AST/RecursiveASTVisitor.h>
+
+using namespace clang;
+
+namespace loplugin
+{
+
+typedef std::vector< const Stmt* > StmtParents;
+
+class UnusedVariableCheck
+    : public RecursiveASTVisitor< UnusedVariableCheck >
+    {
+    public:
+        explicit UnusedVariableCheck( ASTContext& context );
+        void run();
+        bool VisitNamedDecl( NamedDecl* declaration );
+    private:
+        ASTContext& context;
+    };
+
+} // namespace
+
+#endif // UNUSEDVARIABLECHECK_H
diff --git a/config_host.mk.in b/config_host.mk.in
index 48710b1..66cef50 100644
--- a/config_host.mk.in
+++ b/config_host.mk.in
@@ -71,6 +71,7 @@ export COMMONS_HTTPCLIENT_JAR=@COMMONS_HTTPCLIENT_JAR@
 export COMMONS_LANG_JAR=@COMMONS_LANG_JAR@
 export COMMONS_LOGGING_JAR=@COMMONS_LOGGING_JAR@
 export COMPATH=@COMPATH@
+export COMPILER_PLUGINS=@COMPILER_PLUGINS@
 export COMP_ENV=@OUTPATH@
 export COM_FOR_BUILD=@COM_FOR_BUILD@
 export CPPUNIT_CFLAGS=@CPPUNIT_CFLAGS@
diff --git a/configure.in b/configure.in
index 01960af..00d50bd 100644
--- a/configure.in
+++ b/configure.in
@@ -789,6 +789,11 @@ AC_ARG_ENABLE(dbgutil,
          It is not possible to mix object files or libraries from a
          --enable-dbgutil and a --disable-dbgutil build.]))
 
+AC_ARG_ENABLE(compiler-plugins,
+    AS_HELP_STRING([--enable-compiler-plugins],
+        [Enable compiler plugins that will perform additional checks during
+         building. Enabled automatically by --enable-dbgutil.]))
+
 AC_ARG_ENABLE(linkoo,
     AS_HELP_STRING([--disable-linkoo],
         [Disable linkoo for the smoketest installation.]))
@@ -4951,6 +4956,40 @@ fi
 AC_SUBST([VALGRIND_CFLAGS])
 
 dnl ===================================================================
+dnl Compiler plugins
+dnl ===================================================================
+
+COMPILER_PLUGINS=
+# currently only Clang
+if test "$COM_GCC_IS_CLANG" = "TRUE"; then
+    if test -n "$enable_compiler_plugins"; then
+        compiler_plugins="$enable_compiler_plugins"
+    elif test -n "$enable_dbgutil" -a "$enable_dbgutil" != "no"; then
+        compiler_plugins=test
+    else
+        compiler_plugins=no
+    fi
+    if test "$compiler_plugins" != "no"; then
+        AC_LANG_PUSH([C++])
+        save_CPPFLAGS=$CPPFLAGS
+        CPPFLAGS="$CPPFLAGS -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS"
+        AC_CHECK_HEADER(clang/AST/RecursiveASTVisitor.h,
+            [COMPILER_PLUGINS=TRUE],
+            [
+            if test "$compiler_plugins" = "yes"; then
+                AC_MSG_ERROR([Cannot find Clang headers to build compiler plugins.])
+            else
+                AC_MSG_WARN([Cannot find Clang headers to build compiler plugins, plugins 
disabled])
+                add_warning "Cannot find Clang headers to build compiler plugins, plugins 
disabled."
+            fi
+            ])
+        CPPFLAGS=$save_CPPFLAGS
+        AC_LANG_POP([C++])
+    fi
+fi
+AC_SUBST(COMPILER_PLUGINS)
+
+dnl ===================================================================
 dnl Set the MinGW sys-root
 dnl ===================================================================
 if test "$WITH_MINGW" = "yes"; then
diff --git a/solenv/gbuild/platform/com_GCC_class.mk b/solenv/gbuild/platform/com_GCC_class.mk
index 630eed7..aa00267 100644
--- a/solenv/gbuild/platform/com_GCC_class.mk
+++ b/solenv/gbuild/platform/com_GCC_class.mk
@@ -60,6 +60,7 @@ $(call gb_Helper_abbreviate_dirs,\
                $(if $(filter Library,$(TARGETTYPE)),$(gb_Library_LTOFLAGS)) \
                $(if $(VISIBILITY),,$(gb_VISIBILITY_FLAGS)) \
                $(if $(WARNINGS_NOT_ERRORS),,$(gb_CFLAGS_WERROR)) \
+               $(if $(COMPILER_PLUGINS),$(gb_COMPILER_PLUGINS)) \
                $(T_CFLAGS) \
                -c $(3) \
                -o $(1) \
@@ -82,6 +83,7 @@ $(call gb_Helper_abbreviate_dirs,\
                $(if $(filter Library,$(TARGETTYPE)),$(gb_Library_LTOFLAGS)) \
                $(if $(VISIBILITY),,$(gb_VISIBILITY_FLAGS)) \
                $(if $(WARNINGS_NOT_ERRORS),,$(gb_CXXFLAGS_WERROR)) \
+               $(if $(COMPILER_PLUGINS),$(gb_COMPILER_PLUGINS)) \
                $(T_CXXFLAGS) \
                -c $(3) \
                -o $(1) \
diff --git a/solenv/gbuild/platform/com_GCC_defs.mk b/solenv/gbuild/platform/com_GCC_defs.mk
index 0cc86e3..3d73d5c 100644
--- a/solenv/gbuild/platform/com_GCC_defs.mk
+++ b/solenv/gbuild/platform/com_GCC_defs.mk
@@ -149,6 +149,12 @@ gb_DEBUG_CXXFLAGS := $(FNO_DEFAULT_INLINE)
 gb_LinkTarget_INCLUDE := $(filter-out %/stl, $(subst -I. , ,$(SOLARINC)))
 gb_LinkTarget_INCLUDE_STL := $(filter %/stl, $(subst -I. , ,$(SOLARINC)))
 
+ifeq ($(COM_GCC_IS_CLANG),TRUE)
+gb_COMPILER_PLUGINS :=-Xclang -load -Xclang $(SRCDIR)/compilerplugins/obj/compileplugin.so -Xclang 
-add-plugin -Xclang loplugin
+else
+gb_COMPILER_PLUGINS :=
+endif
+
 # Executable class
 
 gb_Executable_EXT_for_build :=
-- 
1.7.10.4


Context


Privacy Policy | Impressum (Legal Info) | Copyright information: Unless otherwise specified, all text and images on this website are licensed under the Creative Commons Attribution-Share Alike 3.0 License. This does not include the source code of LibreOffice, which is licensed under the Mozilla Public License (MPLv2). "LibreOffice" and "The Document Foundation" are registered trademarks of their corresponding registered owners or are in actual use as trademarks in one or more countries. Their respective logos and icons are also subject to international copyright laws. Use thereof is explained in our trademark policy.