diff --git a/CMakeLists.txt b/CMakeLists.txt index 1997ed3..6137de6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,148 +1,155 @@ cmake_minimum_required (VERSION 2.6) project (ClangLazy) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake) find_package(Clang 3.6 MODULE REQUIRED) set( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) set( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib ) add_definitions (-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS) add_definitions (-D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H) +OPTION(CLAZY_ON_WINDOWS_HACK "Enable this option if you're using a patched clang to support plugins on Windows" OFF) +if(CLAZY_ON_WINDOWS_HACK) + message("Using Windows plugin support hack") + ADD_DEFINITIONS(-DCLAZY_ON_WINDOWS_HACK) +endif(CLAZY_ON_WINDOWS_HACK) + + if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings -fno-exceptions -fno-rtti") elseif(MSVC) # disable trigger-happy warnings from Clang/LLVM headers set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4244 /wd4291 /wd4800") endif() set (CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,suppress") if(NOT WIN32) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() # Look for std::regex support message("Looking for std::regex support...") try_run(RUN_RESULT COMPILE_RESULT ${CMAKE_BINARY_DIR} ${CMAKE_SOURCE_DIR}/cmake_has_regex_test.cpp) if (RUN_RESULT EQUAL 0) set(HAS_STD_REGEX TRUE) else() set(HAS_STD_REGEX FALSE) endif() # Don't link against LLVMSupport, causes: CommandLine Error: Option 'view-background' registered more than once! STRING(REPLACE " " ";" LLVM_LIBS_LIST ${LLVM_LIBS}) # Transform into a list LIST(REMOVE_ITEM LLVM_LIBS_LIST "-lLLVMSupport") # Remove element macro(add_clang_plugin name) set (srcs ${ARGN}) include_directories(${CLANG_INCLUDE_DIRS} ${CMAKE_SOURCE_DIR}) link_directories("${LLVM_INSTALL_PREFIX}/lib" ${LLVM_LIBRARY_DIRS}) add_library( ${name} SHARED ${srcs} ) if (SYMBOL_FILE) set_target_properties( ${name} PROPERTIES LINK_FlAGS "-exported_symbols_list ${SYMBOL_FILE}") endif() foreach (clang_lib ${CLANG_LIBS}) target_link_libraries( ${name} ${clang_lib} ) endforeach() foreach (llvm_lib ${LLVM_LIBS_LIST}) target_link_libraries( ${name} ${llvm_lib} ) endforeach() foreach (user_lib ${USER_LIBS}) target_link_libraries( ${name} ${user_lib} ) endforeach() endmacro(add_clang_plugin) set(SYMBOL_FILE Lazy.exports) set(SRC_FILES checkbase.cpp checkmanager.cpp checks/autounexpectedqstringbuilder.cpp checks/assertwithsideeffects.cpp checks/container-anti-pattern.cpp checks/container-inside-loop.cpp checks/copyable-polymorphic.cpp checks/detachingbase.cpp checks/detachingmember.cpp checks/detachingtemporary.cpp checks/dynamic_cast.cpp checks/foreach.cpp checks/globalconstcharpointer.cpp checks/isempty-vs-count.cpp checks/inefficientqlistbase.cpp checks/inefficientqlist.cpp checks/inefficient-qlist-soft.cpp checks/implicitcasts.cpp checks/lambda-in-connect.cpp checks/qdatetimeutc.cpp checks/qgetenv.cpp checks/qvariant-template-instantiation.cpp checks/function-args-by-ref.cpp checks/function-args-by-value.cpp checks/qdeleteall.cpp checks/qfileinfo-exists.cpp checks/qmapkey.cpp checks/qstringarg.cpp checks/qstringref.cpp checks/qstring-allocations.cpp checks/qstring-insensitive-allocation.cpp checks/qt4-qstring-from-array.cpp checks/missing-type-info.cpp checks/missing-qobject-macro.cpp checks/nonpodstatic.cpp checks/range-loop.cpp checks/requiredresults.cpp checks/reservecandidates.cpp checks/ruleofbase.cpp checks/ruleoftwosoft.cpp checks/ruleofthree.cpp checks/temporaryiterator.cpp checks/unused-non-trivial-variable.cpp checks/virtualcallsfromctor.cpp checks/writingtotemporary.cpp checks/wrong-qglobalstatic.cpp Clazy.cpp ContextUtils.cpp FixItUtils.cpp HierarchyUtils.cpp LoopUtils.cpp MacroUtils.cpp TemplateUtils.cpp StringUtils.cpp TypeUtils.cpp QtUtils.cpp Utils.cpp) if (HAS_STD_REGEX) set(SRC_FILES ${SRC_FILES} checks/oldstyleconnect.cpp) else() message("old-style-connect check is disabled due to missing std::regex support") endif() add_clang_plugin(ClangLazy ${SRC_FILES}) set_target_properties(ClangLazy PROPERTIES LINKER_LANGUAGE CXX PREFIX "") include("GNUInstallDirs") install(TARGETS ClangLazy RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) if(NOT WIN32) install(FILES ${CMAKE_SOURCE_DIR}/clazy DESTINATION bin PERMISSIONS OWNER_WRITE OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE) else() install(FILES ${CMAKE_SOURCE_DIR}/clazy.bat DESTINATION bin PERMISSIONS OWNER_WRITE OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE) endif() diff --git a/README b/README index 809c9a6..7413846 100644 --- a/README +++ b/README @@ -1,173 +1,196 @@ -------------------------------------------------------------------------------- SOURCE CODE You can get clazy from: https://github.com/KDE/clazy git@git.kde.org:clazy http://anongit.kde.org/clazy -------------------------------------------------------------------------------- -BUILD INSTRUCTIONS +BUILD INSTRUCTIONS (Linux) * Install needed dependencies: OpenSUSE tumbleweed: zypper install cmake git-core llvm llvm-devel llvm-clang llvm-clang-devel Ubuntu-15.10: apt-get install g++ cmake clang llvm git-core libclang-3.6-dev Archlinux: pacman -S make llvm clang python2 cmake qt5-base git gcc * Build and install clang >= 3.6 if your distro doesn't provide it $ git clone https://github.com/llvm-mirror/llvm.git $ cd /tools/ && git clone https://github.com/llvm-mirror/clang.git $ cd /projects && git clone https://github.com/llvm-mirror/compiler-rt.git $ mkdir /build && cd /build $ cmake -DCMAKE_INSTALL_PREFIX= -DLLVM_TARGETS_TO_BUILD=X86 -DCMAKE_BUILD_TYPE=Release .. $ make -jX && make install -* Build the clang-lazy plugin +* Build the clazy plugin + $ cd clazy/ $ cmake -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release $ make && make install See troubleshooting section if you have problems. +-------------------------------------------------------------------------------- +BUILD INSTRUCTIONS (Windows) + +The instructions assume your terminal is suitable for development (msvc2013). +jom, nmake, git, cmake and cl should be in your PATH. + +* Build and install llvm and clang from master (3.9) + > git clone https://github.com/llvm-mirror/llvm.git + > cd \tools\ && git clone https://github.com/llvm-mirror/clang.git + > cd clang + > git cherry-pick ae1cd1e7c301954bab703e9116a30b330902d43a + > git cherry-pick bce41007c954eafd1d2fdcecbf4cc007697901e7 + > mkdir \build && cd \build + > cmake -DCMAKE_INSTALL_PREFIX=c:\my_install_folder\llvm\ -DLLVM_TARGETS_TO_BUILD="X64" -DCMAKE_BUILD_TYPE=Release -G "NMake Makefiles JOM" .. + > jom + > nmake install + > Add c:\my_install_folder\llvm\ to PATH + +* Build the clazy plugin + > cd clazy\ + > cmake -DCMAKE_INSTALL_PREFIX=c:\my_install_folder\llvm\ -DCMAKE_BUILD_TYPE=Release -G "NMake Makefiles JOM" -DCLAZY_ON_WINDOWS_HACK=ON + > jom && nmake install -------------------------------------------------------------------------------- SETTING UP YOUR PROJECT TO BUILD WITH CLAZY You should now have the clazy command available to you, in /bin/. Compile your programs with it instead of clang++/g++. Note that this command is just a convenience wrapper which calls: clang++ -Xclang -load -Xclang ClangLazy.so -Xclang -add-plugin -Xclang clang-lazy To build a CMake project use cmake . -DCMAKE_CXX_COMPILER=clazy and rebuild. To make it the compiler for qmake projects, just run qmake like: qmake -spec linux-clang QMAKE_CXX="clazy" Alternatively, if you want to use clang directly, without the wrapper: qmake -spec linux-clang QMAKE_CXXFLAGS="-Xclang -load -Xclang ClangLazy.so -Xclang -add-plugin -Xclang clang-lazy" You can also edit mkspecs/common/clang.conf and change QMAKE_CXX to clazy instead of clang++ and run qmake -spec linux-clang You're all set, clazy will now run some checks on your project, but not all of them. Read on if you want to enable/disable which checks are run. -------------------------------------------------------------------------------- SELECTING WHICH CHECKS TO ENABLE You may want to choose which checks to enable before starting to compile. There are many checks and they are divided in levels: Checks from level0: container-anti-pattern wrong-qglobalstatic writing-to-temporary qstring-insensitive-allocation qvariant-template-instantiation qstring-ref (fix-missing-qstringref) temporary-iterator qstring-arg qmap-with-key-pointer qdatetime-utc (fix-qdatetime-utc) qgetenv (fix-qgetenv) qfileinfo-exists Checks from level1: range-loop non-pod-global-static missing-qobject-macro qdeleteall inefficient-qlist-soft foreach detaching-temporary auto-unexpected-qstringbuilder (fix-auto-unexpected-qstringbuilder) Checks from level2: qstring-allocations (fix-qlatin1string-allocations,fix-fromLatin1_fromUtf8-allocations,fix-fromCharPtrAllocations) rule-of-two-soft rule-of-three reserve-candidates virtual-call-ctor old-style-connect (fix-old-style-connect) function-args-by-ref implicit-casts global-const-char-pointer container-inside-loop Checks from level3: bogus-dynamic-cast detaching-member copyable-polymorphic assert-with-side-effects Description of each level: level0: Very stable checks, 100% safe, no false-positives level1: Similar to level0, but sometimes (rarely) there might be some false-positives level2: Sometimes has false-positives (20-30%). level3: Not always correct, possibly very noisy, might require a knowledgeable developer to review, might have a very big rate of false-positives, might have bugs. If you don't specify anything all checks from level0 and level1 will run. To specify a list of checks to run, or to choose a level, you can use the CLAZY_CHECKS env variable or pass arguments to the compiler. Example via env variable: export CLAZY_CHECKS="bogus-dynamic-cast,qmap-with-key-pointer,virtual-call-ctor" # Enables only these 3 checks export CLAZY_CHECKS="level0" # Enables all checks from level0 export CLAZY_CHECKS="level0,detaching-temporary" # Enables all from level0 and also detaching-temporary Example via compiler argument: clazy -Xclang -plugin-arg-clang-lazy -Xclang level0,detaching-temporary Don't forget to re-run cmake/qmake/etc if you altered the c++ flags to specify flags. -------------------------------------------------------------------------------- ENABLING FIXITS Some checks support fixits, in which clazy will re-write your source files whenever it can fix something. You can enable a fixit through the env variable, for example: export CLAZY_FIXIT="fix-qlatin1string-allocations" Only one fixit can be enabled each time. WARNING: Backup your code, don't blame me if a fixit is not applied correctly. For better results don't use parallel builds, otherwise a fixit being applied in an header file might be done twice. -------------------------------------------------------------------------------- TROUBLESHOOTING - clang: symbol lookup error: /usr/lib/x86_64-linux-gnu/ClangLazy.so: undefined symbol: _ZNK5clang15DeclarationName11getAsStringEv This is due to mixing ABIs. Your clang/llvm was compiled with the new gcc c++ ABI [1] but you compiled the clazy plugin with clang (which uses old ABI [2]). The solution is to build the clazy plugin with gcc or use a distro which hasn't migrated to gcc5 ABI yet, such as archlinux. [1] https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html [2] https://llvm.org/bugs/show_bug.cgi?id=23529 - [Fedora 23] cmake can't find LLVM ? Looks like /usr/share/llvm/cmake/LLVM-Config.cmake is buggy. Better build your own llvm/clang. - Some checks are misteriously not producing warnings or not applying fixits ? Check if you have ccache interfering and turn it off -------------------------------------------------------------------------------- REDUCING WARNING NOISE - If you think you found a false-positive, file a bug report. - If you want to suppress warnings from headers of Qt or 3rd party code, include them with -isystem instead of -I -------------------------------------------------------------------------------- REPORTING BUGS AND WISHES bug tracker: https://bugs.kde.org/enter_bug.cgi?product=clazy IRC: #kde-clazy (freenode) E-mail: smartins@kde.org -------------------------------------------------------------------------------- CONTRIBUTING PATCHES https://git.reviewboard.kde.org --------------------------------------------------------------------------------