diff options
-rw-r--r-- | autobuild.xml | 78 | ||||
-rwxr-xr-x | build.sh | 29 | ||||
-rw-r--r-- | indra/cmake/CMakeLists.txt | 1 | ||||
-rw-r--r-- | indra/cmake/Copy3rdPartyLibs.cmake | 14 | ||||
-rw-r--r-- | indra/cmake/Variables.cmake | 1 | ||||
-rw-r--r-- | indra/cmake/bugsplat.cmake | 26 | ||||
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 5 | ||||
-rw-r--r-- | indra/llcommon/llapp.cpp | 23 | ||||
-rw-r--r-- | indra/llcommon/llpreprocessor.h | 2 | ||||
-rw-r--r-- | indra/llcommon/stringize.h | 52 | ||||
-rw-r--r-- | indra/llcommon/tests/wrapllerrs.h | 14 | ||||
-rw-r--r-- | indra/newview/CMakeLists.txt | 100 | ||||
-rw-r--r-- | indra/newview/Info-SecondLife.plist | 2 | ||||
-rw-r--r-- | indra/newview/llappdelegate-objc.mm | 51 | ||||
-rw-r--r-- | indra/newview/llappviewermacosx-for-objc.h | 35 | ||||
-rw-r--r-- | indra/newview/llappviewermacosx.cpp | 11 | ||||
-rw-r--r-- | indra/newview/llappviewerwin32.cpp | 120 | ||||
-rw-r--r-- | indra/newview/llversioninfo.cpp | 7 | ||||
-rw-r--r-- | indra/newview/tests/llversioninfo_test.cpp | 6 | ||||
-rwxr-xr-x | indra/newview/viewer_manifest.py | 343 |
20 files changed, 681 insertions, 239 deletions
diff --git a/autobuild.xml b/autobuild.xml index feb4260c18..285449fa5a 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -225,6 +225,60 @@ <key>version</key> <string>1.57</string> </map> + <key>bugsplat</key> + <map> + <key>copyright</key> + <string>Copyright 2003-2017, BugSplat</string> + <key>description</key> + <string>Bugsplat crash reporting package</string> + <key>license</key> + <string>Proprietary</string> + <key>license_file</key> + <string>LICENSES/BUGSPLAT_LICENSE.txt</string> + <key>name</key> + <string>bugsplat</string> + <key>platforms</key> + <map> + <key>darwin64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>45d772624651dd2ec256ebc4be5fdb5e</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/19829/138853/bugsplat-1.0.2.516501-darwin64-516501.tar.bz2</string> + </map> + <key>name</key> + <string>darwin64</string> + </map> + <key>windows</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>7fca1d1d04b8e926a6afd14fff206ff0</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/19831/138867/bugsplat-3.5.0.5.516501-windows-516501.tar.bz2</string> + </map> + <key>name</key> + <string>windows</string> + </map> + <key>windows64</key> + <map> + <key>archive</key> + <map> + <key>hash</key> + <string>dc760b8760e6f8a8d27de3a9d7adf5c1</string> + <key>url</key> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/19830/138860/bugsplat-3.5.0.5.516501-windows64-516501.tar.bz2</string> + </map> + <key>name</key> + <string>windows64</string> + </map> + </map> + <key>version</key> + <string>1.0.2.516501</string> + </map> <key>chardet</key> <map> <key>copyright</key> @@ -1692,7 +1746,7 @@ <key>darwin</key> <map> <key>archive</key> - <map> + <map> <key>hash</key> <string>3855bd40f950e3c22739ae8f3ee2afc9</string> <key>url</key> @@ -1705,10 +1759,10 @@ <map> <key>archive</key> <map> - <key>hash</key> + <key>hash</key> <string>d1521becaf21bf7233173722af63f57d</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15257/98440/kdu-7.10.4.513518-darwin64-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15257/98440/kdu-7.10.4.513518-darwin64-513518.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -1717,10 +1771,10 @@ <map> <key>archive</key> <map> - <key>hash</key> + <key>hash</key> <string>43d7a6a69a54534a736f132e9c81795b</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15255/98451/kdu-7.10.4.513518-linux-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15255/98451/kdu-7.10.4.513518-linux-513518.tar.bz2</string> </map> <key>name</key> <string>linux</string> @@ -1752,11 +1806,11 @@ <key>windows64</key> <map> <key>archive</key> - <map> + <map> <key>hash</key> <string>da3b1ea90797b189d80ab5d50fdf05d4</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15260/98469/kdu-7.10.4.513518-windows64-513518.tar.bz2</string> + <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15260/98469/kdu-7.10.4.513518-windows64-513518.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -3260,9 +3314,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>86f6708f393c162cd4f92426b0a3cde7</string> + <string>3919570e9edecac56c1ef2d334370dc5</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/15341/99062/viewer_manager-1.0.513570-darwin64-513570.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/19742/138074/viewer_manager-1.0.516441-darwin64-516441.tar.bz2</string> </map> <key>name</key> <string>darwin64</string> @@ -3284,9 +3338,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>c4dec51062ad78c09b11f7432aff4d1d</string> + <string>39add158bc6c4f975d7e17db34db8981</string> <key>url</key> - <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/17857/121832/viewer_manager-1.0.515286-windows-515286.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/19744/138154/viewer_manager-1.0.516441-windows-516441.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -3297,7 +3351,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>source_type</key> <string>hg</string> <key>version</key> - <string>1.0.515286</string> + <string>1.0.516441</string> </map> <key>vlc-bin</key> <map> @@ -95,26 +95,37 @@ pre_build() && [ -r "$master_message_template_checkout/message_template.msg" ] \ && template_verifier_master_url="-DTEMPLATE_VERIFIER_MASTER_URL=file://$master_message_template_checkout/message_template.msg" - # nat 2016-12-20: disable HAVOK on Mac until we get a 64-bit Mac build. RELEASE_CRASH_REPORTING=ON HAVOK=ON SIGNING=() - if [ "$arch" == "Darwin" ] - then - if [ "$variant" == "Release" ] - then SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ - "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") + if [ "$arch" == "Darwin" -a "$variant" == "Release" ] + then SIGNING=("-DENABLE_SIGNING:BOOL=YES" \ + "-DSIGNING_IDENTITY:STRING=Developer ID Application: Linden Research, Inc.") + fi + + # don't spew credentials into build log + bugsplat_sh="$build_secrets_checkout/bugsplat/bugsplat.sh" + set +x + if [ -r "$bugsplat_sh" ] + then # show that we're doing this, just not the contents + echo source "$bugsplat_sh" + source "$bugsplat_sh" + # important: we test this and use its value in [grand-]child processes + if [ -n "${BUGSPLAT_DB:-}" ] + then echo export BUGSPLAT_DB + export BUGSPLAT_DB + echo RELEASE_CRASH_REPORTING=OFF + RELEASE_CRASH_REPORTING=OFF fi fi + set -x "$autobuild" configure --quiet -c $variant -- \ -DPACKAGE:BOOL=ON \ - -DUNATTENDED:BOOL=ON \ -DHAVOK:BOOL="$HAVOK" \ -DRELEASE_CRASH_REPORTING:BOOL="$RELEASE_CRASH_REPORTING" \ -DVIEWER_CHANNEL:STRING="${viewer_channel}" \ -DGRID:STRING="\"$viewer_grid\"" \ - -DLL_TESTS:BOOL="$run_tests" \ -DTEMPLATE_VERIFIER_OPTIONS:STRING="$template_verifier_options" $template_verifier_master_url \ "${SIGNING[@]}" \ || fatal "$variant configuration failed" @@ -194,6 +205,8 @@ then exit 1 fi +shopt -s nullglob # if nothing matches a glob, expand to nothing + initialize_build # provided by master buildscripts build.sh begin_section "autobuild initialize" diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 4a3ebe4835..84e1c5d6fd 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -12,6 +12,7 @@ set(cmake_SOURCE_FILES Audio.cmake BerkeleyDB.cmake Boost.cmake + bugsplat.cmake BuildVersion.cmake CEFPlugin.cmake CEFPlugin.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 09a97fc03e..c9519b0e1d 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -49,6 +49,20 @@ if(WINDOWS) libhunspell.dll ) + # Filenames are different for 32/64 bit BugSplat file and we don't + # have any control over them so need to branch. + if (DEFINED ENV{BUGSPLAT_DB}) + if(ADDRESS_SIZE EQUAL 32) + set(release_files ${release_files} BugSplat.dll) + set(release_files ${release_files} BugSplatRc.dll) + set(release_files ${release_files} BsSndRpt.exe) + else(ADDRESS_SIZE EQUAL 32) + set(release_files ${release_files} BugSplat64.dll) + set(release_files ${release_files} BugSplatRc64.dll) + set(release_files ${release_files} BsSndRpt64.exe) + endif(ADDRESS_SIZE EQUAL 32) + endif (DEFINED ENV{BUGSPLAT_DB}) + if (FMODEX) if(ADDRESS_SIZE EQUAL 32) diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake index bd69c49856..b913d6398e 100644 --- a/indra/cmake/Variables.cmake +++ b/indra/cmake/Variables.cmake @@ -209,7 +209,6 @@ set(SIGNING_IDENTITY "" CACHE STRING "Specifies the signing identity to use, if set(VERSION_BUILD "0" CACHE STRING "Revision number passed in from the outside") set(USESYSTEMLIBS OFF CACHE BOOL "Use libraries from your system rather than Linden-supplied prebuilt libraries.") -set(UNATTENDED OFF CACHE BOOL "Should be set to ON for building with VC Express editions.") set(USE_PRECOMPILED_HEADERS ON CACHE BOOL "Enable use of precompiled header directives where supported.") diff --git a/indra/cmake/bugsplat.cmake b/indra/cmake/bugsplat.cmake new file mode 100644 index 0000000000..eb5808b1fb --- /dev/null +++ b/indra/cmake/bugsplat.cmake @@ -0,0 +1,26 @@ +# BugSplat is engaged by setting environment variable BUGSPLAT_DB to the +# target BugSplat database name prior to running CMake (and during autobuild +# build). +if (DEFINED ENV{BUGSPLAT_DB}) + if (USESYSTEMLIBS) + message(STATUS "Looking for system BugSplat") + set(BUGSPLAT_FIND_QUIETLY ON) + set(BUGSPLAT_FIND_REQUIRED ON) + include(FindBUGSPLAT) + else (USESYSTEMLIBS) + message(STATUS "Engaging autobuild BugSplat") + include(Prebuilt) + use_prebuilt_binary(bugsplat) + if (WINDOWS) + set(BUGSPLAT_LIBRARIES + ${ARCH_PREBUILT_DIRS_RELEASE}/bugsplat.lib + ) + elseif (DARWIN) + find_library(BUGSPLAT_LIBRARIES BugsplatMac + PATHS "${ARCH_PREBUILT_DIRS_RELEASE}") + else (WINDOWS) + + endif (WINDOWS) + set(BUGSPLAT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/bugsplat) + endif (USESYSTEMLIBS) +endif (DEFINED ENV{BUGSPLAT_DB}) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index d9eb13d65a..8977acb873 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -255,6 +255,11 @@ set(llcommon_HEADER_FILES set_source_files_properties(${llcommon_HEADER_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) +if (DEFINED ENV{BUGSPLAT_DB}) + set_source_files_properties(llapp.cpp + PROPERTIES COMPILE_DEFINITIONS "LL_BUGSPLAT") +endif (DEFINED ENV{BUGSPLAT_DB}) + list(APPEND llcommon_SOURCE_FILES ${llcommon_HEADER_FILES}) if(LLCOMMON_LINK_SHARED) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 6cc9e804d4..421af3006e 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -392,7 +392,7 @@ void LLApp::setupErrorHandling(bool second_instance) #if LL_WINDOWS -#if LL_SEND_CRASH_REPORTS +#if LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) EnableCrashingOnCrashes(); // This sets a callback to handle w32 signals to the console window. @@ -454,8 +454,15 @@ void LLApp::setupErrorHandling(bool second_instance) mExceptionHandler->set_handle_debug_exceptions(true); } } -#endif -#else +#endif // LL_SEND_CRASH_REPORTS && ! defined(LL_BUGSPLAT) +#else // ! LL_WINDOWS + +#if defined(LL_BUGSPLAT) + // Don't install our own signal handlers -- BugSplat needs to hook them, + // or it's completely ineffectual. + bool installHandler = false; + +#else // ! LL_BUGSPLAT // // Start up signal handling. // @@ -463,9 +470,11 @@ void LLApp::setupErrorHandling(bool second_instance) // thread, asynchronous signals can be delivered to any thread (in theory) // setup_signals(); - + // Add google breakpad exception handler configured for Darwin/Linux. bool installHandler = true; +#endif // ! LL_BUGSPLAT + #if LL_DARWIN // For the special case of Darwin, we do not want to install the handler if // the process is being debugged as the app will exit with value ABRT (6) if @@ -498,7 +507,7 @@ void LLApp::setupErrorHandling(bool second_instance) // installing the handler. installHandler = true; } - #endif + #endif // ! LL_RELEASE_FOR_DOWNLOAD if(installHandler && (mExceptionHandler == 0)) { @@ -514,9 +523,9 @@ void LLApp::setupErrorHandling(bool second_instance) google_breakpad::MinidumpDescriptor desc(mDumpPath); mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); } -#endif +#endif // LL_LINUX -#endif +#endif // ! LL_WINDOWS startErrorThread(); } diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 2879038c36..ef015fdce4 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -198,6 +198,8 @@ #define LL_TO_STRING_HELPER(x) #x #define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) +#define LL_TO_WSTRING_HELPER(x) L#x +#define LL_TO_WSTRING(x) LL_TO_WSTRING_HELPER(x) #define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg #define LL_GLUE_IMPL(x, y) x##y #define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y) diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index a5a90d7297..38dd198ad3 100644 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -30,7 +30,6 @@ #define LL_STRINGIZE_H #include <sstream> -#include <boost/phoenix/phoenix.hpp> #include <llstring.h> /** @@ -53,12 +52,7 @@ std::basic_string<CHARTYPE> gstringize(const T& item) */ inline std::string stringize(const std::wstring& item) { - LL_WARNS() << "WARNING: Possible narrowing" << LL_ENDL; - - std::string s; - - s = wstring_to_utf8str(item); - return gstringize<char>(s); + return wstring_to_utf8str(item); } /** @@ -76,7 +70,10 @@ std::string stringize(const T& item) */ inline std::wstring wstringize(const std::string& item) { - return gstringize<wchar_t>(item.c_str()); + // utf8str_to_wstring() returns LLWString, which isn't necessarily the + // same as std::wstring + LLWString s(utf8str_to_wstring(item)); + return std::wstring(s.begin(), s.end()); } /** @@ -91,10 +88,10 @@ std::wstring wstringize(const T& item) /** * stringize_f(functor) */ -template <typename Functor> -std::string stringize_f(Functor const & f) +template <typename CHARTYPE, typename Functor> +std::basic_string<CHARTYPE> stringize_f(Functor const & f) { - std::ostringstream out; + std::basic_ostringstream<CHARTYPE> out; f(out); return out.str(); } @@ -108,31 +105,37 @@ std::string stringize_f(Functor const & f) * return out.str(); * @endcode */ -#define STRINGIZE(EXPRESSION) (stringize_f(boost::phoenix::placeholders::arg1 << EXPRESSION)) +#define STRINGIZE(EXPRESSION) (stringize_f<char>([&](std::ostream& out){ out << EXPRESSION; })) +/** + * WSTRINGIZE() is the wstring equivalent of STRINGIZE() + */ +#define WSTRINGIZE(EXPRESSION) (stringize_f<wchar_t>([&](std::wostream& out){ out << EXPRESSION; })) /** * destringize(str) * defined for symmetry with stringize - * *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding + * @NOTE - this has distinct behavior from boost::lexical_cast<T> regarding * leading/trailing whitespace and handling of bad_lexical_cast exceptions + * @NOTE - no need for dewstringize(), since passing std::wstring will Do The + * Right Thing */ -template <typename T> -T destringize(std::string const & str) +template <typename T, typename CHARTYPE> +T destringize(std::basic_string<CHARTYPE> const & str) { - T val; - std::istringstream in(str); - in >> val; + T val; + std::basic_istringstream<CHARTYPE> in(str); + in >> val; return val; } /** * destringize_f(str, functor) */ -template <typename Functor> -void destringize_f(std::string const & str, Functor const & f) +template <typename CHARTYPE, typename Functor> +void destringize_f(std::basic_string<CHARTYPE> const & str, Functor const & f) { - std::istringstream in(str); + std::basic_istringstream<CHARTYPE> in(str); f(in); } @@ -143,8 +146,11 @@ void destringize_f(std::string const & str, Functor const & f) * std::istringstream in(str); * in >> item1 >> item2 >> item3 ... ; * @endcode + * @NOTE - once we get generic lambdas, we shouldn't need DEWSTRINGIZE() any + * more since DESTRINGIZE() should do the right thing with a std::wstring. But + * until then, the lambda we pass must accept the right std::basic_istream. */ -#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::phoenix::placeholders::arg1 >> EXPRESSION))) - +#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::istream& in){in >> EXPRESSION;})) +#define DEWSTRINGIZE(STR, EXPRESSION) (destringize_f((STR), [&](std::wistream& in){in >> EXPRESSION;})) #endif /* ! defined(LL_STRINGIZE_H) */ diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 9a4bbbd630..08fbf19b1c 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -109,6 +109,12 @@ public: mMessages.push_back(message); } + friend inline + std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log) + { + return log.streamto(out); + } + /// Don't assume the message we want is necessarily the LAST log message /// emitted by the underlying code; search backwards through all messages /// for the sought string. @@ -126,7 +132,7 @@ public: throw tut::failure(STRINGIZE("failed to find '" << search << "' in captured log messages:\n" - << boost::ref(*this))); + << *this)); } std::ostream& streamto(std::ostream& out) const @@ -200,10 +206,4 @@ private: LLError::RecorderPtr mRecorder; }; -inline -std::ostream& operator<<(std::ostream& out, const CaptureLogRecorder& log) -{ - return log.streamto(out); -} - #endif /* ! defined(LL_WRAPLLERRS_H) */ diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index b7a860aae0..d6a0d2860b 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -3,7 +3,14 @@ project(viewer) include(00-Common) +# DON'T move Linking.cmake to its place in the alphabetized list below: it +# sets variables on which the 3p .cmake files depend. +include(Linking) + include(Boost) +if (DEFINED ENV{BUGSPLAT_DB}) + include(bugsplat) +endif (DEFINED ENV{BUGSPLAT_DB}) include(BuildPackagesInfo) include(BuildVersion) include(CMakeCopyIfDifferent) @@ -37,7 +44,6 @@ include(LLUI) include(LLVFS) include(LLWindow) include(LLXML) -include(Linking) include(NDOF) include(NVAPI) include(OPENAL) @@ -93,6 +99,12 @@ include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ) +if (DEFINED ENV{BUGSPLAT_DB}) + include_directories( + ${BUGSPLAT_INCLUDE_DIR} + ) +endif (DEFINED ENV{BUGSPLAT_DB}) + include_directories(SYSTEM ${LLCOMMON_SYSTEM_INCLUDE_DIRS} ${LLXML_SYSTEM_INCLUDE_DIRS} @@ -1354,6 +1366,14 @@ if (DARWIN) # This should be compiled with the viewer. LIST(APPEND viewer_SOURCE_FILES llappdelegate-objc.mm) + set_source_files_properties( + llappdelegate-objc.mm + PROPERTIES + COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" + # BugsplatMac is a module, imported with @import. That language feature + # demands these switches. + COMPILE_FLAGS "-fmodules -fcxx-modules" + ) find_library(AGL_LIBRARY AGL) find_library(APPKIT_LIBRARY AppKit) @@ -1368,6 +1388,12 @@ if (DARWIN) ${COREAUDIO_LIBRARY} ) + if (DEFINED ENV{BUGSPLAT_DB}) + list(APPEND viewer_LIBRARIES + ${BUGSPLAT_LIBRARIES} + ) + endif (DEFINED ENV{BUGSPLAT_DB}) + # Add resource files to the project. set(viewer_RESOURCE_FILES secondlife.icns @@ -1393,6 +1419,11 @@ endif (DARWIN) if (LINUX) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux.cpp) + set_source_files_properties( + llappviewerlinux.cpp + PROPERTIES + COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" + ) LIST(APPEND viewer_SOURCE_FILES llappviewerlinux_api_dbus.cpp) SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed") @@ -1409,6 +1440,11 @@ if (WINDOWS) llappviewerwin32.cpp llwindebug.cpp ) + set_source_files_properties( + llappviewerwin32.cpp + PROPERTIES + COMPILE_DEFINITIONS "${VIEWER_CHANNEL_VERSION_DEFINES}" + ) list(APPEND viewer_HEADER_FILES llappviewerwin32.h @@ -1691,6 +1727,11 @@ if (SDL_FOUND) ) endif (SDL_FOUND) +if (DEFINED ENV{BUGSPLAT_DB}) + set_property(TARGET ${VIEWER_BINARY_NAME} + PROPERTY COMPILE_DEFINITIONS "LL_BUGSPLAT") +endif (DEFINED ENV{BUGSPLAT_DB}) + # add package files file(GLOB EVENT_HOST_SCRIPT_GLOB_LIST ${CMAKE_CURRENT_SOURCE_DIR}/../viewer_components/*.py) @@ -1789,7 +1830,7 @@ if (WINDOWS) ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll ) endif (FMODEX) - + add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat COMMAND ${PYTHON_EXECUTABLE} @@ -1824,24 +1865,9 @@ if (WINDOWS) add_dependencies(${VIEWER_BINARY_NAME} SLPlugin - windows-crash-logger + windows-crash-logger ) - # sets the 'working directory' for debugging from visual studio. - if (NOT UNATTENDED) - add_custom_command( - TARGET ${VIEWER_BINARY_NAME} POST_BUILD - COMMAND ${CMAKE_SOURCE_DIR}/tools/vstool/vstool.exe - ARGS - --solution - ${CMAKE_BINARY_DIR}/${CMAKE_PROJECT_NAME}.sln - --workingdir - ${VIEWER_BINARY_NAME} - "${CMAKE_CURRENT_SOURCE_DIR}" - COMMENT "Setting the ${VIEWER_BINARY_NAME} working directory for debugging." - ) - endif (NOT UNATTENDED) - if (PACKAGE) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/event_host.tar.bz2 @@ -1903,8 +1929,8 @@ else (WINDOWS) endif (WINDOWS) # *NOTE: - this list is very sensitive to ordering, test carefully on all -# platforms if you change the releative order of the entries here. -# In particular, cmake 2.6.4 (when buidling with linux/makefile generators) +# platforms if you change the relative order of the entries here. +# In particular, cmake 2.6.4 (when building with linux/makefile generators) # appears to sometimes de-duplicate redundantly listed dependencies improperly. # To work around this, higher level modules should be listed before the modules # that they depend upon. -brad @@ -1979,6 +2005,12 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${LLAPPEARANCE_LIBRARIES} ) +if (DEFINED ENV{BUGSPLAT_DB}) + target_link_libraries(${VIEWER_BINARY_NAME} + ${BUGSPLAT_LIBRARIES} + ) +endif (DEFINED ENV{BUGSPLAT_DB}) + set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH "Path to artwork files.") @@ -2052,25 +2084,35 @@ if (LINUX) endif (LINUX) if (DARWIN) - # These all get set with PROPERTIES - set(product "Second Life") + # These all get set with PROPERTIES. It's not that the property names are + # magically known to CMake -- it's that these names are referenced in the + # Info-SecondLife.plist file in the configure_file() directive below. + set(product "${VIEWER_CHANNEL}") # this is the setting for the Python wrapper, see SL-322 and WRAPPER line in Info-SecondLife.plist set(MACOSX_WRAPPER_EXECUTABLE_NAME "SL_Launcher") - set(MACOSX_BUNDLE_INFO_STRING "Second Life Viewer") + set(MACOSX_BUNDLE_INFO_STRING "${VIEWER_CHANNEL}") set(MACOSX_BUNDLE_ICON_FILE "secondlife.icns") set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.secondlife.indra.viewer") set(MACOSX_BUNDLE_LONG_VERSION_STRING "${VIEWER_CHANNEL} ${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_NAME "SecondLife") - set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}") + set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${VIEWER_SHORT_VERSION}.${VIEWER_VERSION_REVISION}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${VIEWER_SHORT_VERSION}${VIEWER_MACOSX_PHASE}${VIEWER_REVISION}") set(MACOSX_BUNDLE_COPYRIGHT "Copyright © Linden Research, Inc. 2007") set(MACOSX_BUNDLE_NSMAIN_NIB_FILE "SecondLife.nib") set(MACOSX_BUNDLE_NSPRINCIPAL_CLASS "NSApplication") + + # https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/ + set(CMAKE_MACOSX_RPATH 1) set_target_properties( ${VIEWER_BINARY_NAME} PROPERTIES OUTPUT_NAME "${product}" + # From Contents/MacOS/SecondLife, look in Contents/Frameworks + INSTALL_RPATH "@loader_path/../Frameworks" + # SIGH, as of 2018-05-24 (cmake 3.11.1) the INSTALL_RPATH property simply + # does not work. Try this: + LINK_FLAGS "-rpath @loader_path/../Frameworks" MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist" ) @@ -2141,7 +2183,7 @@ if (INSTALL) include(${CMAKE_CURRENT_SOURCE_DIR}/ViewerInstall.cmake) endif (INSTALL) -if (PACKAGE) +if (PACKAGE AND (RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) AND NOT DEFINED ENV{BUGSPLAT_DB}) set(SYMBOL_SEARCH_DIRS "") # Note that the path to VIEWER_SYMBOL_FILE must match that in ../../build.sh if (WINDOWS) @@ -2160,8 +2202,8 @@ if (PACKAGE) list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/mac_crash_logger/${CMAKE_CFG_INTDIR}") list(APPEND SYMBOL_SEARCH_DIRS "${CMAKE_BINARY_DIR}/media_plugins/gstreamer010/${CMAKE_CFG_INTDIR}") set(VIEWER_SYMBOL_FILE "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/secondlife-symbols-darwin-$ENV{AUTOBUILD_ADDRSIZE}.tar.bz2") - set(VIEWER_EXE_GLOBS "'Second Life' SLPlugin mac-crash-logger") - set(VIEWER_EXE_GLOBS "'Second Life' mac-crash-logger") + set(VIEWER_EXE_GLOBS "'${product}' SLPlugin mac-crash-logger") + set(VIEWER_EXE_GLOBS "'${product}' mac-crash-logger") set(VIEWER_LIB_GLOB "*.dylib") endif (DARWIN) if (LINUX) @@ -2173,7 +2215,6 @@ if (PACKAGE) set(VIEWER_COPY_MANIFEST copy_l_viewer_manifest) endif (LINUX) - if(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) if(CMAKE_CFG_INTDIR STREQUAL ".") set(LLBUILD_CONFIG ${CMAKE_BUILD_TYPE}) else(CMAKE_CFG_INTDIR STREQUAL ".") @@ -2200,8 +2241,7 @@ if (PACKAGE) add_dependencies(generate_breakpad_symbols "${VIEWER_COPY_MANIFEST}") endif (WINDOWS OR LINUX) add_dependencies(llpackage generate_breakpad_symbols) - endif(RELEASE_CRASH_REPORTING OR NON_RELEASE_CRASH_REPORTING) -endif (PACKAGE) +endif () if (LL_TESTS) # To add a viewer unit test, just add the test .cpp file below diff --git a/indra/newview/Info-SecondLife.plist b/indra/newview/Info-SecondLife.plist index af4cf26ac6..8aabd6818b 100644 --- a/indra/newview/Info-SecondLife.plist +++ b/indra/newview/Info-SecondLife.plist @@ -21,7 +21,7 @@ <key>CFBundlePackageType</key> <string>APPL</string> <key>CFBundleShortVersionString</key> - <string>${MACOSX_BUNDLE_LONG_VERSION_STRING}</string> + <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> diff --git a/indra/newview/llappdelegate-objc.mm b/indra/newview/llappdelegate-objc.mm index aebae4c434..4510f4070f 100644 --- a/indra/newview/llappdelegate-objc.mm +++ b/indra/newview/llappdelegate-objc.mm @@ -25,7 +25,14 @@ */ #import "llappdelegate-objc.h" +#if defined(LL_BUGSPLAT) +@import BugsplatMac; +// derived from BugsplatMac's BugsplatTester/AppDelegate.m +@interface LLAppDelegate () <BugsplatStartupManagerDelegate> +@end +#endif #include "llwindowmacosx-objc.h" +#include "llappviewermacosx-for-objc.h" #include <Carbon/Carbon.h> // Used for Text Input Services ("Safe" API - it's supported) @implementation LLAppDelegate @@ -64,6 +71,14 @@ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageUpdated) name:@"NSTextInputContextKeyboardSelectionDidChangeNotification" object:nil]; // [[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL]; + +#if defined(LL_BUGSPLAT) + // https://www.bugsplat.com/docs/platforms/os-x#initialization +// [BugsplatStartupManager sharedManager].autoSubmitCrashReport = YES; +// [BugsplatStartupManager sharedManager].askUserDetails = NO; + [BugsplatStartupManager sharedManager].delegate = self; + [[BugsplatStartupManager sharedManager] start]; +#endif } - (void) handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent { @@ -179,4 +194,40 @@ return true; } +#if defined(LL_BUGSPLAT) + +#if 0 +// Apparently this override method only contributes the User Description field +// of BugSplat's All Crashes table. Despite the method name, it would seem to +// be a bad place to try to stuff all of SecondLife.log. +- (NSString *)applicationLogForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager +{ +// return NSStringFromSelector(_cmd); + infos("Reached applicationLogForBugsplatStartupManager"); + return @"[contents of SecondLife.log]"; +} +#endif + +- (BugsplatAttachment *)attachmentForBugsplatStartupManager:(BugsplatStartupManager *)bugsplatStartupManager { + // We get the *old* log file pathname (for SecondLife.old) because it's on + // the run *following* the crash that BugsplatStartupManager notices that + // the previous run crashed and calls this override. By that time, we've + // already renamed SecondLife.log to SecondLife.old. + std::string logfile = getOldLogFilePathname(); + NSString *ns_logfile = [NSString stringWithCString:logfile.c_str() + encoding:NSUTF8StringEncoding]; + NSData *data = [NSData dataWithContentsOfFile:ns_logfile]; + + // Apologies for the hard-coded log-file basename, but I do not know the + // incantation for "$(basename "$logfile")" in this language. + BugsplatAttachment *attachment = + [[BugsplatAttachment alloc] initWithFilename:@"SecondLife.log" + attachmentData:data + contentType:@"text/plain"]; + infos("attachmentForBugsplatStartupManager: attaching " + logfile); + return attachment; +} + +#endif // LL_BUGSPLAT + @end diff --git a/indra/newview/llappviewermacosx-for-objc.h b/indra/newview/llappviewermacosx-for-objc.h new file mode 100644 index 0000000000..c439297611 --- /dev/null +++ b/indra/newview/llappviewermacosx-for-objc.h @@ -0,0 +1,35 @@ +/** + * @file llappviewermacosx-for-objc.h + * @author Nat Goodspeed + * @date 2018-06-15 + * @brief llappviewermacosx.h publishes the C++ API for + * llappviewermacosx.cpp, just as + * llappviewermacosx-objc.h publishes the Objective-C++ API for + * llappviewermacosx-objc.mm. + * + * This header is intended to publish for Objective-C++ consumers a + * subset of the C++ API presented by llappviewermacosx.cpp. It's a + * subset because, if an Objective-C++ consumer were to #include + * the full llappviewermacosx.h, we would almost surely run into + * trouble due to the discrepancy between Objective-C++'s BOOL versus + * classic Microsoft/Linden BOOL. + * + * $LicenseInfo:firstyear=2018&license=viewerlgpl$ + * Copyright (c) 2018, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H) +#define LL_LLAPPVIEWERMACOSX_FOR_OBJC_H + +#include <string> + +bool initViewer(); +void handleUrl(const char* url_utf8); +bool pumpMainLoop(); +void handleQuit(); +void cleanupViewer(); +std::string getOldLogFilePathname(); +void infos(const std::string& message); + +#endif /* ! defined(LL_LLAPPVIEWERMACOSX_FOR_OBJC_H) */ diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index d472f8926b..d014e992f9 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -36,6 +36,7 @@ #include "llappviewermacosx-objc.h" #include "llappviewermacosx.h" +#include "llappviewermacosx-for-objc.h" #include "llwindowmacosx-objc.h" #include "llcommandlineparser.h" @@ -147,6 +148,16 @@ void cleanupViewer() gViewerAppPtr = NULL; } +std::string getOldLogFilePathname() +{ + return gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.old"); +} + +void infos(const std::string& message) +{ + LL_INFOS() << message << LL_ENDL; +} + int main( int argc, char **argv ) { // Store off the command line args for use later. diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 48b3a1c485..3efc94d7b5 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -66,8 +66,70 @@ #endif #include "stringize.h" +#include "lldir.h" +#include <fstream> #include <exception> + +// Bugsplat (http://bugsplat.com) crash reporting tool +#ifdef LL_BUGSPLAT +#include "BugSplat.h" +#include "reader.h" // JsonCpp + +namespace +{ + // MiniDmpSender's constructor is defined to accept __wchar_t* instead of + // plain wchar_t*. That said, wunder() returns std::basic_string<__wchar_t>, + // NOT plain __wchar_t*, despite the apparent convenience. Calling + // wunder(something).c_str() as an argument expression is fine: that + // std::basic_string instance will survive until the function returns. + // Calling c_str() on a std::basic_string local to wunder() would be + // Undefined Behavior: we'd be left with a pointer into a destroyed + // std::basic_string instance. + + // It would be nice if, when wchar_t is the same as __wchar_t, this whole + // function would optimize away. However, we use it only for the arguments + // to make exactly one call to initialize BugSplat. + inline std::basic_string<__wchar_t> wunder(const std::wstring& str) + { + return { str.begin(), str.end() }; + } + + // when what we have in hand is a std::string, convert from UTF-8 using + // specific wstringize() overload + inline std::basic_string<__wchar_t> wunder(const std::string& str) + { + return wunder(wstringize(str)); + } + + // Irritatingly, MiniDmpSender::setCallback() is defined to accept a + // classic-C function pointer instead of an arbitrary C++ callable. If it + // did accept a modern callable, we could pass a lambda that binds our + // MiniDmpSender pointer. As things stand, though, we must define an + // actual function and store the pointer statically. + static MiniDmpSender *sBugSplatSender = nullptr; + + bool bugsplatSendLog(UINT nCode, LPVOID lpVal1, LPVOID lpVal2) + { + // If we haven't yet initialized LLDir, don't bother trying to + // find our log file. + // Alternatively -- if we might encounter trouble trying to query + // LLDir during crash cleanup -- consider making gDirUtilp an + // LLPounceable, and attach a callback that stores the pathname to + // the log file here. + if (nCode == MDSCB_EXCEPTIONCODE && gDirUtilp) + { + // send the main viewer log file + // widen to wstring, convert to __wchar_t, then pass c_str() + sBugSplatSender->sendAdditionalFile( + wunder(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "SecondLife.log")).c_str()); + } + + return false; + } +} +#endif // LL_BUGSPLAT + namespace { void (*gOldTerminateHandler)() = NULL; @@ -495,15 +557,65 @@ bool LLAppViewerWin32::init() LLWinDebug::instance(); #endif -#if LL_WINDOWS #if LL_SEND_CRASH_REPORTS - +#if ! defined(LL_BUGSPLAT) LLAppViewer* pApp = LLAppViewer::instance(); pApp->initCrashReporting(); -#endif -#endif +#else // LL_BUGSPLAT + + std::string build_data_fname( + gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "build_data.json")); + std::ifstream inf(build_data_fname.c_str()); + if (! inf.is_open()) + { + LL_WARNS() << "Can't initialize BugSplat, can't read '" << build_data_fname + << "'" << LL_ENDL; + } + else + { + Json::Reader reader; + Json::Value build_data; + if (! reader.parse(inf, build_data, false)) // don't collect comments + { + // gah, the typo is baked into their API + LL_WARNS() << "Can't initialize BugSplat, can't parse '" << build_data_fname + << "': " << reader.getFormatedErrorMessages() << LL_ENDL; + } + else + { + Json::Value BugSplat_DB = build_data["BugSplat DB"]; + if (! BugSplat_DB) + { + LL_WARNS() << "Can't initialize BugSplat, no 'BugSplat DB' entry in '" + << build_data_fname << "'" << LL_ENDL; + } + else + { + // Got BugSplat_DB, onward! + std::wstring version_string(WSTRINGIZE(LL_VIEWER_VERSION_MAJOR << '.' << + LL_VIEWER_VERSION_MINOR << '.' << + LL_VIEWER_VERSION_PATCH << '.' << + LL_VIEWER_VERSION_BUILD)); + + // have to convert normal wide strings to strings of __wchar_t + sBugSplatSender = new MiniDmpSender( + wunder(BugSplat_DB.asString()).c_str(), + wunder(LL_TO_WSTRING(LL_VIEWER_CHANNEL)).c_str(), + wunder(version_string).c_str(), + nullptr); + sBugSplatSender->setCallback(bugsplatSendLog); + + // engage stringize() overload that converts from wstring + LL_INFOS() << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) + << stringize(version_string) << ')' << LL_ENDL; + } // got BugSplat_DB + } // parsed build_data.json + } // opened build_data.json + +#endif // LL_BUGSPLAT +#endif // LL_SEND_CRASH_REPORTS bool success = LLAppViewer::init(); diff --git a/indra/newview/llversioninfo.cpp b/indra/newview/llversioninfo.cpp index 375dce485d..4e07223784 100644 --- a/indra/newview/llversioninfo.cpp +++ b/indra/newview/llversioninfo.cpp @@ -101,14 +101,11 @@ namespace { // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The // macro expands to the string name of the channel, but without quotes. We - // need to turn it into a quoted string. This macro trick does that. -#define stringize_inner(x) #x -#define stringize_outer(x) stringize_inner(x) - + // need to turn it into a quoted string. LL_TO_STRING() does that. /// Storage of the channel name the viewer is using. // The channel name is set by hardcoded constant, // or by calling LLVersionInfo::resetChannel() - std::string sWorkingChannelName(stringize_outer(LL_VIEWER_CHANNEL)); + std::string sWorkingChannelName(LL_TO_STRING(LL_VIEWER_CHANNEL)); // Storage for the "version and channel" string. // This will get reset too. diff --git a/indra/newview/tests/llversioninfo_test.cpp b/indra/newview/tests/llversioninfo_test.cpp index 2f7a4e9601..58f0469552 100644 --- a/indra/newview/tests/llversioninfo_test.cpp +++ b/indra/newview/tests/llversioninfo_test.cpp @@ -33,10 +33,8 @@ // LL_VIEWER_CHANNEL is a macro defined on the compiler command line. The // macro expands to the string name of the channel, but without quotes. We -// need to turn it into a quoted string. This macro trick does that. -#define stringize_inner(x) #x -#define stringize_outer(x) stringize_inner(x) -#define ll_viewer_channel stringize_outer(LL_VIEWER_CHANNEL) +// need to turn it into a quoted string. LL_TO_STRING() does that. +#define ll_viewer_channel LL_TO_STRING(LL_VIEWER_CHANNEL) namespace tut { diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 541112a765..49dc732457 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -26,19 +26,20 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA $/LicenseInfo$ """ -import sys -import os -import os.path -import shutil import errno import json +import os +import os.path import plistlib import random import re +import shutil import stat import subprocess +import sys import tarfile import time +import zipfile viewer_dir = os.path.dirname(__file__) # Add indra/lib/python to our path so we don't have to muck with PYTHONPATH. @@ -186,6 +187,11 @@ class ViewerManifest(LLManifest): "Address Size":self.address_size, "Update Service":"https://update.secondlife.com/update", } + try: + build_data_dict["BugSplat DB"] = os.environ["BUGSPLAT_DB"] + except KeyError: + # skip the assignment if there's no BUGSPLAT_DB variable + pass build_data_dict = self.finish_build_data_dict(build_data_dict) with open(os.path.join(os.pardir,'build_data.json'), 'w') as build_data_handle: json.dump(build_data_dict,build_data_handle) @@ -580,6 +586,16 @@ class WindowsManifest(ViewerManifest): # Hunspell self.path("libhunspell.dll") + # BugSplat + if(self.address_size == 64): + self.path("BsSndRpt64.exe") + self.path("BugSplat64.dll") + self.path("BugSplatRc64.dll") + else: + self.path("BsSndRpt.exe") + self.path("BugSplat.dll") + self.path("BugSplatRc.dll") + # For google-perftools tcmalloc allocator. try: if self.args['configuration'].lower() == 'debug': @@ -589,7 +605,6 @@ class WindowsManifest(ViewerManifest): except: print "Skipping libtcmalloc_minimal.dll" - self.path(src="licenses-win32.txt", dst="licenses.txt") self.path("featuretable.txt") @@ -597,106 +612,107 @@ class WindowsManifest(ViewerManifest): self.path("ca-bundle.crt") # Media plugins - CEF - with self.prefix(src='../media_plugins/cef/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_cef.dll") - - # Media plugins - LibVLC - with self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_libvlc.dll") - - # Media plugins - Example (useful for debugging - not shipped with release viewer) - if self.channel_type() != 'release': - with self.prefix(src='../media_plugins/example/%s' % self.args['configuration'], dst="llplugin"): - self.path("media_plugin_example.dll") - - # CEF runtime files - debug - # CEF runtime files - not debug (release, relwithdebinfo etc.) - config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' - with self.prefix(src=os.path.join(pkgdir, 'bin', config), dst="llplugin"): - self.path("chrome_elf.dll") - self.path("d3dcompiler_43.dll") - self.path("d3dcompiler_47.dll") - self.path("libcef.dll") - self.path("libEGL.dll") - self.path("libGLESv2.dll") - self.path("dullahan_host.exe") - self.path("natives_blob.bin") - self.path("snapshot_blob.bin") - self.path("widevinecdmadapter.dll") - - # MSVC DLLs needed for CEF and have to be in same directory as plugin - with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release'), dst="llplugin"): - self.path("msvcp120.dll") - self.path("msvcr120.dll") - - # CEF files common to all configurations - with self.prefix(src=os.path.join(pkgdir, 'resources'), dst="llplugin"): - self.path("cef.pak") - self.path("cef_100_percent.pak") - self.path("cef_200_percent.pak") - self.path("cef_extensions.pak") - self.path("devtools_resources.pak") - self.path("icudtl.dat") - - with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst=os.path.join('llplugin', 'locales')): - self.path("am.pak") - self.path("ar.pak") - self.path("bg.pak") - self.path("bn.pak") - self.path("ca.pak") - self.path("cs.pak") - self.path("da.pak") - self.path("de.pak") - self.path("el.pak") - self.path("en-GB.pak") - self.path("en-US.pak") - self.path("es-419.pak") - self.path("es.pak") - self.path("et.pak") - self.path("fa.pak") - self.path("fi.pak") - self.path("fil.pak") - self.path("fr.pak") - self.path("gu.pak") - self.path("he.pak") - self.path("hi.pak") - self.path("hr.pak") - self.path("hu.pak") - self.path("id.pak") - self.path("it.pak") - self.path("ja.pak") - self.path("kn.pak") - self.path("ko.pak") - self.path("lt.pak") - self.path("lv.pak") - self.path("ml.pak") - self.path("mr.pak") - self.path("ms.pak") - self.path("nb.pak") - self.path("nl.pak") - self.path("pl.pak") - self.path("pt-BR.pak") - self.path("pt-PT.pak") - self.path("ro.pak") - self.path("ru.pak") - self.path("sk.pak") - self.path("sl.pak") - self.path("sr.pak") - self.path("sv.pak") - self.path("sw.pak") - self.path("ta.pak") - self.path("te.pak") - self.path("th.pak") - self.path("tr.pak") - self.path("uk.pak") - self.path("vi.pak") - self.path("zh-CN.pak") - self.path("zh-TW.pak") - - with self.prefix(src=os.path.join(pkgdir, 'bin', 'release'), dst="llplugin"): - self.path("libvlc.dll") - self.path("libvlccore.dll") - self.path("plugins/") + with self.prefix(dst="llplugin"): + with self.prefix(src='../media_plugins/cef/%s' % self.args['configuration']): + self.path("media_plugin_cef.dll") + + # Media plugins - LibVLC + with self.prefix(src='../media_plugins/libvlc/%s' % self.args['configuration']): + self.path("media_plugin_libvlc.dll") + + # Media plugins - Example (useful for debugging - not shipped with release viewer) + if self.channel_type() != 'release': + with self.prefix(src='../media_plugins/example/%s' % self.args['configuration']): + self.path("media_plugin_example.dll") + + # CEF runtime files - debug + # CEF runtime files - not debug (release, relwithdebinfo etc.) + config = 'debug' if self.args['configuration'].lower() == 'debug' else 'release' + with self.prefix(src=os.path.join(pkgdir, 'bin', config)): + self.path("chrome_elf.dll") + self.path("d3dcompiler_43.dll") + self.path("d3dcompiler_47.dll") + self.path("libcef.dll") + self.path("libEGL.dll") + self.path("libGLESv2.dll") + self.path("dullahan_host.exe") + self.path("natives_blob.bin") + self.path("snapshot_blob.bin") + self.path("widevinecdmadapter.dll") + + # MSVC DLLs needed for CEF and have to be in same directory as plugin + with self.prefix(src=os.path.join(os.pardir, 'sharedlibs', 'Release')): + self.path("msvcp120.dll") + self.path("msvcr120.dll") + + # CEF files common to all configurations + with self.prefix(src=os.path.join(pkgdir, 'resources')): + self.path("cef.pak") + self.path("cef_100_percent.pak") + self.path("cef_200_percent.pak") + self.path("cef_extensions.pak") + self.path("devtools_resources.pak") + self.path("icudtl.dat") + + with self.prefix(src=os.path.join(pkgdir, 'resources', 'locales'), dst='locales'): + self.path("am.pak") + self.path("ar.pak") + self.path("bg.pak") + self.path("bn.pak") + self.path("ca.pak") + self.path("cs.pak") + self.path("da.pak") + self.path("de.pak") + self.path("el.pak") + self.path("en-GB.pak") + self.path("en-US.pak") + self.path("es-419.pak") + self.path("es.pak") + self.path("et.pak") + self.path("fa.pak") + self.path("fi.pak") + self.path("fil.pak") + self.path("fr.pak") + self.path("gu.pak") + self.path("he.pak") + self.path("hi.pak") + self.path("hr.pak") + self.path("hu.pak") + self.path("id.pak") + self.path("it.pak") + self.path("ja.pak") + self.path("kn.pak") + self.path("ko.pak") + self.path("lt.pak") + self.path("lv.pak") + self.path("ml.pak") + self.path("mr.pak") + self.path("ms.pak") + self.path("nb.pak") + self.path("nl.pak") + self.path("pl.pak") + self.path("pt-BR.pak") + self.path("pt-PT.pak") + self.path("ro.pak") + self.path("ru.pak") + self.path("sk.pak") + self.path("sl.pak") + self.path("sr.pak") + self.path("sv.pak") + self.path("sw.pak") + self.path("ta.pak") + self.path("te.pak") + self.path("th.pak") + self.path("tr.pak") + self.path("uk.pak") + self.path("vi.pak") + self.path("zh-CN.pak") + self.path("zh-TW.pak") + + with self.prefix(src=os.path.join(pkgdir, 'bin', 'release')): + self.path("libvlc.dll") + self.path("libvlccore.dll") + self.path("plugins/") # pull in the crash logger and updater from other projects # tag:"crash-logger" here as a cue to the exporter @@ -888,6 +904,9 @@ class DarwinManifest(ViewerManifest): launcher_app, launcher_icon = "Second Life Launcher.app", "secondlife.icns" viewer_app, viewer_icon = "Second Life Viewer.app", "secondlife.icns" + # capture the path to the directory containing toplevel_app + parentdir = os.path.join(self.get_dst_prefix(), os.pardir) + # copy over the build result (this is a no-op if run within the xcode script) self.path(os.path.join(self.args['configuration'], toplevel_app), dst="") @@ -899,10 +918,7 @@ class DarwinManifest(ViewerManifest): # top-level Second Life application is only a container with self.prefix(src="", dst="Contents"): # everything goes in Contents # top-level Info.plist is as generated by CMake - Info_plist = "Info.plist" - ## This self.path() call reports 0 files... skip? - self.path(Info_plist) - Info_plist = self.dst_path_of(Info_plist) + Info_plist = self.dst_path_of("Info.plist") # the one file in top-level MacOS directory is the trampoline to # our nested launcher_app @@ -984,25 +1000,7 @@ open "%s" --args "$@" # -------------------- nested viewer_app --------------------- with self.prefix(dst=os.path.join(viewer_app, "Contents")): - # Info.plist is just like top-level one... - Info = plistlib.readPlist(Info_plist) - # except for these replacements: - # (CFBundleExecutable may be moot: SL_Launcher directly - # runs the executable, instead of launching the app) - Info["CFBundleExecutable"] = "Second Life" - Info["CFBundleIconFile"] = viewer_icon - self.put_in_file( - plistlib.writePlistToString(Info), - os.path.basename(Info_plist), - "Info.plist") - - # CEF framework goes inside viewer_app/Contents/Frameworks. - # Remember where we parked this car. - with self.prefix(src="", dst="Frameworks"): - CEF_framework = "Chromium Embedded Framework.framework" - self.path2basename(relpkgdir, CEF_framework) - CEF_framework = self.dst_path_of(CEF_framework) - + # defer Info.plist until after MacOS with self.prefix(dst="MacOS"): # CMake constructs the Second Life executable in the # MacOS directory belonging to the top-level Second @@ -1015,23 +1013,94 @@ open "%s" --args "$@" # don't move the trampoline script we just made! continue fromwhere = os.path.join(toplevel_MacOS, f) - towhere = os.path.join(here, f) + towhere = self.dst_path_of(f) print "Moving %s => %s" % \ (self.relpath(fromwhere, relbase), self.relpath(towhere, relbase)) # now do it, only without relativizing paths os.rename(fromwhere, towhere) - # NOTE: the -S argument to strip causes it to keep - # enough info for annotated backtraces (i.e. function - # names in the crash log). 'strip' with no arguments - # yields a slightly smaller binary but makes crash - # logs mostly useless. This may be desirable for the - # final release. Or not. + # Pick the biggest of the executables as the real viewer. + # Make (basename, fullpath) pairs; for each pair, + # expand to (size, basename, fullpath) triples; sort + # by size; pick the last triple; take the basename and + # fullpath from that. + _, exename, exepath = \ + sorted((os.path.getsize(path), name, path) + for name, path in + ((name, os.path.join(here, name)) + for name in os.listdir(here)))[-1] + if ("package" in self.args['actions'] or "unpacked" in self.args['actions']): - self.run_command( - ['strip', '-S', self.dst_path_of('Second Life')]) + # only if we're engaging BugSplat + if "BUGSPLAT_DB" in os.environ: + # Create a symbol archive BEFORE stripping the + # binary. + self.run_command(['dsymutil', exepath]) + # This should produce a Second Life.dSYM bundle directory. + try: + # Now pretend we're Xcode making a .xcarchive file. + # Put it as a sibling of the top-level .app. + # From "Dave" at BugSplat support: + # "More from our Mac lead: I think zipping + # a folder containing the binary and + # symbols would be sufficient. Assuming + # symbol files are created with CMake. I'm + # not sure if CMake strips symbols into + # separate files at build time, and if so + # they're in a supported format." + xcarchive = os.path.join(parentdir, + exename + '.xcarchive.zip') + with zipfile.ZipFile(xcarchive, 'w', + compression=zipfile.ZIP_DEFLATED) as zf: + print "Creating {}".format(xcarchive) + for base, dirs, files in os.walk(here): + for fn in files: + fullfn = os.path.join(base, fn) + relfn = os.path.relpath(fullfn, here) + print " {}".format(relfn) + zf.write(fullfn, relfn) + finally: + # Whether or not we were able to create the + # .xcarchive file, clean up the .dSYM bundle + shutil.rmtree(self.dst_path_of(exename + '.dSYM')) + + # NOTE: the -S argument to strip causes it to keep + # enough info for annotated backtraces (i.e. function + # names in the crash log). 'strip' with no arguments + # yields a slightly smaller binary but makes crash + # logs mostly useless. This may be desirable for the + # final release. Or not. + self.run_command(['strip', '-S', exepath]) + + # Info.plist is just like top-level one... + Info = plistlib.readPlist(Info_plist) + # except for these replacements: + # (CFBundleExecutable may be moot: SL_Launcher directly + # runs the executable, instead of launching the app) + Info["CFBundleExecutable"] = exename + Info["CFBundleIconFile"] = viewer_icon + try: + # https://www.bugsplat.com/docs/platforms/os-x#configuration + Info["BugsplatServerURL"] = \ + "https://{BUGSPLAT_DB}.bugsplatsoftware.com/".format(**os.environ) + except KeyError: + # skip the assignment if there's no BUGSPLAT_DB variable + pass + self.put_in_file( + plistlib.writePlistToString(Info), + os.path.basename(Info_plist), + "Info.plist") + + with self.prefix(src="", dst="Frameworks"): + # CEF framework goes inside viewer_app/Contents/Frameworks. + CEF_framework = "Chromium Embedded Framework.framework" + self.path2basename(relpkgdir, CEF_framework) + # Remember where we parked this car. + CEF_framework = self.dst_path_of(CEF_framework) + + self.path2basename(relpkgdir, "BugsplatMac.framework") with self.prefix(dst="Resources"): # defer cross-platform file copies until we're in the right |