From 858364b385197210698501e14ba5b86e1d02c9da Mon Sep 17 00:00:00 2001 From: malte_langkabel Date: Mon, 22 Aug 2016 14:24:53 +0200 Subject: [PATCH] logic: handle java not found on windows and mac * implemented java will not be used if it is not found on system * add jni libraries weak linked for Mac * use dlopen for lazy library loading * added java path to preferences --- CMakeLists.txt | 27 ++++-- java_indexer/src/io/coati/JavaIndexer.java | 6 +- src/lib/JavaProject.cpp | 3 +- .../parser/java/JavaEnvironmentFactory.cpp | 82 +++++++++++++++---- src/lib_gui/qt/element/QtLocationPicker.cpp | 5 ++ src/lib_gui/qt/element/QtLocationPicker.h | 1 + .../QtProjectWizzardContentPreferences.cpp | 36 ++++++++ .../QtProjectWizzardContentPreferences.h | 7 +- .../data/parser/java/JavaParser.cpp | 24 +++--- 9 files changed, 154 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c67cd31..b2a7e181 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -212,7 +212,11 @@ target_include_directories(${LIB_PROJECT_NAME} SYSTEM "${CMAKE_SOURCE_DIR}/src/external" ) -target_link_libraries(${LIB_PROJECT_NAME} ${Boost_LIBRARIES} ${LIB_LICENSE_PROJECT_NAME} ${JNI_LIBRARIES}) +if (WIN32) + target_link_libraries(${LIB_PROJECT_NAME} ${Boost_LIBRARIES} ${LIB_LICENSE_PROJECT_NAME} ${JNI_LIBRARIES}) +else() + target_link_libraries(${LIB_PROJECT_NAME} ${Boost_LIBRARIES} ${LIB_LICENSE_PROJECT_NAME}) +endif() # Lib Parser ------------------------------------------------------------------- @@ -394,11 +398,24 @@ create_source_groups(${APP_FILES}) target_link_libraries(${APP_PROJECT_NAME} ${LIB_GUI_PROJECT_NAME} ${LIB_PARSER_PROJECT_NAME} ${LIB_PROJECT_NAME} ${LIB_LICENSE_PROJECT_NAME}) if (WIN32) -SET_TARGET_PROPERTIES( - ${APP_PROJECT_NAME} PROPERTIES - LINK_FLAGS "/DELAYLOAD:jvm.dll") + SET_TARGET_PROPERTIES( + ${APP_PROJECT_NAME} PROPERTIES + LINK_FLAGS "/DELAYLOAD:jvm.dll" + ) +elseif (APPLE) + set(LAZY_LIB_FLAGS "") + + foreach (_lib ${JNI_LIBRARIES}) + set (LAZY_LIB_FLAGS "${LAZY_LIB_FLAGS} -lazy_library ${_lib}") + endforeach() + + SET_TARGET_PROPERTIES( + ${APP_PROJECT_NAME} PROPERTIES + LINK_FLAGS ${LAZY_LIB_FLAGS} + ) endif() + set_property( TARGET ${APP_PROJECT_NAME} PROPERTY INCLUDE_DIRECTORIES @@ -601,7 +618,7 @@ target_link_libraries(${TEST_PROJECT_NAME} ${LIB_PARSER_PROJECT_NAME} ${LIB_PROJ if (WIN32) SET_TARGET_PROPERTIES( - ${TEST_PROJECT_NAME} PROPERTIES + ${TEST_PROJECT_NAME} PROPERTIES LINK_FLAGS "/DELAYLOAD:jvm.dll") endif() diff --git a/java_indexer/src/io/coati/JavaIndexer.java b/java_indexer/src/io/coati/JavaIndexer.java index 7f3f2b65..de466923 100644 --- a/java_indexer/src/io/coati/JavaIndexer.java +++ b/java_indexer/src/io/coati/JavaIndexer.java @@ -20,7 +20,7 @@ public class JavaIndexer { public static void processFile(int address, String filePath, String fileContent, String classPath) { - System.out.println("indexing file: " + filePath); +// System.out.println("indexing file: " + filePath); try { @@ -33,8 +33,8 @@ public class JavaIndexer { try { - JarTypeSolver jarTypeSolver = new JarTypeSolver(path); - typeSolver.add(jarTypeSolver); + JarTypeSolver solver = new JarTypeSolver(path); + typeSolver.add(solver); } catch (IOException e) { diff --git a/src/lib/JavaProject.cpp b/src/lib/JavaProject.cpp index 03466d06..25975882 100644 --- a/src/lib/JavaProject.cpp +++ b/src/lib/JavaProject.cpp @@ -2,6 +2,7 @@ #include "data/parser/java/JavaEnvironmentFactory.h" #include "data/parser/java/TaskParseJava.h" +#include "isTrial.h" JavaProject::~JavaProject() { @@ -26,7 +27,7 @@ JavaProject::JavaProject(std::shared_ptr projectSettings, S #else const std::string separator = ":"; #endif - if (!JavaEnvironmentFactory::getInstance()) + if (!JavaEnvironmentFactory::getInstance() && !isTrial()) { JavaEnvironmentFactory::createInstance( "data/java/asm-5.0.3.jar" + separator + diff --git a/src/lib/data/parser/java/JavaEnvironmentFactory.cpp b/src/lib/data/parser/java/JavaEnvironmentFactory.cpp index bd0f095d..af5f5d42 100644 --- a/src/lib/data/parser/java/JavaEnvironmentFactory.cpp +++ b/src/lib/data/parser/java/JavaEnvironmentFactory.cpp @@ -1,10 +1,18 @@ #include "data/parser/java/JavaEnvironmentFactory.h" +#include + +#ifdef __APPLE__ +#include +#endif + #include #include "data/parser/java/JavaEnvironment.h" #include "settings/ApplicationSettings.h" #include "utility/logging/logging.h" +#include "utility/messaging/type/MessageStatus.h" +#include "utility/file/FileSystem.h" void JavaEnvironmentFactory::createInstance(std::string classPath) { @@ -18,24 +26,63 @@ void JavaEnvironmentFactory::createInstance(std::string classPath) { LOG_ERROR("java classpath cannot be changed!"); // todo: implement destroying the old factory instance and create a new one. + // may be not so easy... there can only be one java env per process (which can never be destroyed) -.- return; } } - s_classPath = classPath; + bool javaFound = false; #ifdef _WIN32 - { // todo: make this windows only - std::string env1 = getenv("path"); + { + std::string oldPathContent = getenv("path"); std::string javapath = ApplicationSettings::getInstance()->getJavaPath() + "/client/"; - putenv(("path=" + env1 + ";" + javapath).c_str()); // path env is only modified in the scope of this process. + putenv(("path=" + oldPathContent + ";" + javapath).c_str()); // path env is only modified in the scope of this process. + + javaFound = FileSystem::exists(javapath + "jvm.dll"); } #endif - using namespace std; - JavaVM* jvm; // Pointer to the JVM (Java Virtual Machine) - JNIEnv* env; // Pointer to native interface +#ifdef __APPLE__ + { + std::string javapath = ApplicationSettings::getInstance()->getJavaPath(); + void* handle = nullptr; + + if (javapath.size()) + { + handle = dlopen((javapath + "/jre/lib/server/libjvm.dylib").c_str(), RTLD_NOW); + } + + if (!handle && javapath.size()) + { + handle = dlopen((javapath + "/libjvm.dylib").c_str(), RTLD_NOW); + } + + if (!handle) + { + handle = dlopen("libjvm.dylib", RTLD_NOW); + } + + if (handle) + { + javaFound = true; + } + } +#endif + + if (!javaFound) + { + std::string errorMessage = "Unable to locate Java on this machine."; + LOG_ERROR(errorMessage); + MessageStatus(errorMessage, true, false).dispatch(); + return; + } + + s_classPath = classPath; + + JavaVM* jvm = nullptr; // Pointer to the JVM (Java Virtual Machine) + JNIEnv* env = nullptr; // Pointer to native interface JavaVMInitArgs vm_args; // Initialization arguments JavaVMOption* options = new JavaVMOption[3]; // JVM invocation options @@ -44,38 +91,41 @@ void JavaEnvironmentFactory::createInstance(std::string classPath) options[1].optionString = const_cast("-Xms1m"); std::string maximumMemoryOprionString = "-Xmx" + std::to_string(ApplicationSettings::getInstance()->getJavaMaximumMemory()) + "m"; options[2].optionString = const_cast(maximumMemoryOprionString.c_str()); -// options[3].optionString = "-verbose:jni"; - vm_args.version = JNI_VERSION_1_6; // minimum Java version - vm_args.nOptions = 3; // number of options + vm_args.version = JNI_VERSION_1_6; + vm_args.nOptions = 3; vm_args.options = options; vm_args.ignoreUnrecognized = false; // invalid options make the JVM init fail - jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); // YES !! + jint rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); delete [] options; if(rc != JNI_OK) { + std::string errorMessage; if(rc == JNI_EVERSION) { - LOG_ERROR("JVM is oudated and doesn't meet requirements"); + errorMessage = "JVM is oudated and doesn't meet requirements"; } else if(rc == JNI_ENOMEM) { - LOG_ERROR("not enough memory for JVM"); + errorMessage = "not enough memory for JVM"; } else if(rc == JNI_EINVAL) { - LOG_ERROR("invalid ragument for launching JVM"); + errorMessage = "invalid argument for launching JVM"; } else if(rc == JNI_EEXIST) { - LOG_ERROR("the process can only launch one JVM an not more"); + errorMessage = "the process can only launch one JVM an not more"; } else { - LOG_ERROR_STREAM(<< "could not create the JVM instance (error code " << rc << ")"); + errorMessage = "could not create the JVM instance (error code " + std::to_string(rc) + ")"; } + + LOG_ERROR(errorMessage); + MessageStatus("Error while creating Java environment: " + errorMessage, true, false).dispatch(); } else { diff --git a/src/lib_gui/qt/element/QtLocationPicker.cpp b/src/lib_gui/qt/element/QtLocationPicker.cpp index 7cd61c0a..dac3b658 100644 --- a/src/lib_gui/qt/element/QtLocationPicker.cpp +++ b/src/lib_gui/qt/element/QtLocationPicker.cpp @@ -41,6 +41,11 @@ void QtLocationPicker::paintEvent(QPaintEvent*) style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this); } +void QtLocationPicker::setPlaceholderText(QString text) +{ + m_data->setPlaceholderText(text); +} + QString QtLocationPicker::getText() { return m_data->text(); diff --git a/src/lib_gui/qt/element/QtLocationPicker.h b/src/lib_gui/qt/element/QtLocationPicker.h index 8b78cf9a..1d3ca25d 100644 --- a/src/lib_gui/qt/element/QtLocationPicker.h +++ b/src/lib_gui/qt/element/QtLocationPicker.h @@ -15,6 +15,7 @@ public: virtual void paintEvent(QPaintEvent*) override; + void setPlaceholderText(QString text); QString getText(); void setText(QString text); void clearText(); diff --git a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.cpp b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.cpp index 4618f7e6..3a08ac88 100644 --- a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.cpp +++ b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.cpp @@ -133,6 +133,32 @@ void QtProjectWizzardContentPreferences::populateForm(QGridLayout* layout, int& ); row++; + + layout->setRowMinimumHeight(row++, 20); + + // Java + layout->addWidget(createFormTitle("JAVA"), row, QtProjectWizzardWindow::FRONT_COL, Qt::AlignLeft); + row++; + + // java path + m_javaPath = new QtLocationPicker(this); + m_javaPath->setPickDirectory(true); + m_javaPath->setPlaceholderText(""); + + layout->addWidget(createFormLabel("Java Path"), row, QtProjectWizzardWindow::FRONT_COL, Qt::AlignRight); + layout->addWidget(m_javaPath, row, QtProjectWizzardWindow::BACK_COL); + + addHelpButton( + "Location of your java installation so that dynamic libraries of JVM can be found." + , layout, row + ); + row++; + + layout->setRowMinimumHeight(row++, 20); + + // C/C++ + layout->addWidget(createFormTitle("C/C++"), row, QtProjectWizzardWindow::FRONT_COL, Qt::AlignLeft); + row++; } void QtProjectWizzardContentPreferences::load() @@ -159,6 +185,11 @@ void QtProjectWizzardContentPreferences::load() m_threads->setCurrentIndex(appSettings->getIndexerThreadCount() - 1); m_fatalErrors->setChecked(appSettings->getShowExternalNonFatalErrors()); + + if (m_javaPath) + { + m_javaPath->setText(QString::fromStdString(appSettings->getJavaPath())); + } } void QtProjectWizzardContentPreferences::save() @@ -181,6 +212,11 @@ void QtProjectWizzardContentPreferences::save() appSettings->setIndexerThreadCount(m_threads->currentIndex() + 1); appSettings->setShowExternalNonFatalErrors(m_fatalErrors->isChecked()); + + if (m_javaPath) + { + appSettings->setJavaPath(m_javaPath->getText().toStdString()); + } } bool QtProjectWizzardContentPreferences::check() diff --git a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.h b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.h index 57bb78aa..011d73e3 100644 --- a/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.h +++ b/src/lib_gui/qt/window/project_wizzard/QtProjectWizzardContentPreferences.h @@ -5,6 +5,7 @@ #include #include +#include "qt/element/QtLocationPicker.h" #include "qt/window/project_wizzard/QtProjectWizzardContent.h" class QtProjectWizzardContentPreferences @@ -31,14 +32,16 @@ private: QLineEdit* m_fontFace; QComboBox* m_fontSize; QComboBox* m_tabWidth; + QComboBox* m_colorSchemes; QLineEdit* m_scrollSpeed; + std::vector m_colorSchemePaths; + int m_oldColorSchemeIndex; QComboBox* m_threads; QCheckBox* m_fatalErrors; - std::vector m_colorSchemePaths; - int m_oldColorSchemeIndex; + QtLocationPicker* m_javaPath; }; #endif // QT_PROJECT_WIZZARD_CONTENT_PREFERENCES_H diff --git a/src/lib_parser/data/parser/java/JavaParser.cpp b/src/lib_parser/data/parser/java/JavaParser.cpp index 0736f310..249b77f5 100644 --- a/src/lib_parser/data/parser/java/JavaParser.cpp +++ b/src/lib_parser/data/parser/java/JavaParser.cpp @@ -59,18 +59,22 @@ void JavaParser::parseFiles(const std::vector& filePaths, const Argume void JavaParser::parseFile(const FilePath& filePath, std::shared_ptr textAccess, const Arguments& arguments) { - m_currentFilePath = filePath.str(); - m_client->onFileParsed(FileSystem::getFileInfoForPath(filePath)); - std::string classPath = ""; - for (const FilePath& path: arguments.javaClassPaths) + if (m_javaEnvironment) { - classPath += path.str() + ";"; + m_currentFilePath = filePath.str(); + m_client->onFileParsed(FileSystem::getFileInfoForPath(filePath)); + std::string classPath = ""; + for (const FilePath& path: arguments.javaClassPaths) + { + // the separator used here should be the same as the one used in JavaIndexer.java + classPath += path.str() + ";"; + } + + // remove tabs because they screw with javaparser's location resolver + std::string fileContent = utility::replace(textAccess->getText(), "\t", " "); + + m_javaEnvironment->callStaticVoidMethod("io/coati/JavaIndexer", "processFile", m_id, filePath.str(), fileContent, classPath); } - - // remove tabs because they screw with javaparser's location resolver - std::string fileContent = utility::replace(textAccess->getText(), "\t", " "); - - m_javaEnvironment->callStaticVoidMethod("io/coati/JavaIndexer", "processFile", m_id, filePath.str(), fileContent, classPath); }