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
This commit is contained in:
malte_langkabel
2016-08-22 14:24:53 +02:00
parent 98eb3f124d
commit 858364b385
9 changed files with 154 additions and 37 deletions
+22 -5
View File
@@ -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()
+3 -3
View File
@@ -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)
{
+2 -1
View File
@@ -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<JavaProjectSettings> 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 +
@@ -1,10 +1,18 @@
#include "data/parser/java/JavaEnvironmentFactory.h"
#include <cstdlib>
#ifdef __APPLE__
#include <dlfcn.h>
#endif
#include <jni.h>
#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<char*>("-Xms1m");
std::string maximumMemoryOprionString = "-Xmx" + std::to_string(ApplicationSettings::getInstance()->getJavaMaximumMemory()) + "m";
options[2].optionString = const_cast<char*>(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
{
@@ -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();
@@ -15,6 +15,7 @@ public:
virtual void paintEvent(QPaintEvent*) override;
void setPlaceholderText(QString text);
QString getText();
void setText(QString text);
void clearText();
@@ -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("<jdk_root>");
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()
@@ -5,6 +5,7 @@
#include <QComboBox>
#include <QLineEdit>
#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<FilePath> m_colorSchemePaths;
int m_oldColorSchemeIndex;
QComboBox* m_threads;
QCheckBox* m_fatalErrors;
std::vector<FilePath> m_colorSchemePaths;
int m_oldColorSchemeIndex;
QtLocationPicker* m_javaPath;
};
#endif // QT_PROJECT_WIZZARD_CONTENT_PREFERENCES_H
+14 -10
View File
@@ -59,18 +59,22 @@ void JavaParser::parseFiles(const std::vector<FilePath>& filePaths, const Argume
void JavaParser::parseFile(const FilePath& filePath, std::shared_ptr<TextAccess> 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);
}