Reorganized project to avoid the ".pro not found" by having all the

pro files in the same directory. With this change the android library
now builds properly.

This also fixes the parallel compilation problem that happened when
building using +8 cores.
This commit is contained in:
codestation
2015-03-21 14:48:25 -04:30
parent c223016725
commit 9f790dc788
106 changed files with 13921 additions and 0 deletions

30
cli/cli.pro Normal file
View File

@@ -0,0 +1,30 @@
include(../config.pri)
include(../common/defines.pri)
TARGET = qcma_cli
TEMPLATE += app
QT += network sql
LIBS += -L../common -lqcma_common
SOURCES += \
main_cli.cpp \
singlecoreapplication.cpp \
headlessmanager.cpp
HEADERS += \
singlecoreapplication.h \
headlessmanager.h
# find packages using pkg-config
QT_CONFIG -= no-pkg-config
CONFIG += link_pkgconfig
PKGCONFIG = libvitamtp libavformat libavcodec libavutil libswscale
# Linux-only config
unix:!macx {
man_cli.files = qcma_cli.1
man_cli.path = $$MANDIR
target.path = $$BINDIR
INSTALLS += target man_cli
}

191
cli/headlessmanager.cpp Normal file
View File

@@ -0,0 +1,191 @@
/*
* QCMA: Cross-platform content manager assistant for the PS Vita
*
* Copyright (C) 2013 Codestation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cmaclient.h"
#include "cmautils.h"
#include "sqlitedb.h"
#include "qlistdb.h"
#include "headlessmanager.h"
#include <QCoreApplication>
#include <QSettings>
#include <QTextStream>
#include <sys/socket.h>
#include <unistd.h>
#include <vitamtp.h>
int HeadlessManager::sighup_fd[2];
int HeadlessManager::sigterm_fd[2];
HeadlessManager::HeadlessManager(QObject *obj_parent) :
QObject(obj_parent)
{
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sighup_fd))
qFatal("Couldn't create HUP socketpair");
if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigterm_fd))
qFatal("Couldn't create TERM socketpair");
sn_hup = new QSocketNotifier(sighup_fd[1], QSocketNotifier::Read, this);
connect(sn_hup, SIGNAL(activated(int)), this, SLOT(handleSigHup()));
sn_term = new QSocketNotifier(sigterm_fd[1], QSocketNotifier::Read, this);
connect(sn_term, SIGNAL(activated(int)), this, SLOT(handleSigTerm()));
}
HeadlessManager::~HeadlessManager()
{
VitaMTP_Cleanup();
delete m_db;
}
void HeadlessManager::refreshDatabase()
{
if(m_db->load()) {
return;
}
QTextStream(stdout) << "Database scan has started" << endl;
if(!m_db->rescan()) {
qWarning("No PS Vita system has been registered");
}
}
void HeadlessManager::start()
{
if(VitaMTP_Init() < 0) {
qCritical("Cannot initialize VitaMTP library");
return;
}
if(QSettings().value("useMemoryStorage", true).toBool()) {
m_db = new QListDB();
} else {
m_db = new SQLiteDB();
}
// initializing database for the first use
refreshDatabase();
// send a signal when the update is finished
connect(m_db, SIGNAL(updated(int)), this, SIGNAL(databaseUpdated(int)));
thread_count = 0;
qDebug("Starting cma threads");
CmaClient *client;
QSettings settings;
if(!settings.value("disableUSB", false).toBool()) {
if(!belongsToGroup("vitamtp"))
qCritical() << tr("This user doesn't belong to the vitamtp group, there could be a problem while reading the USB bus.");
usb_thread = new QThread();
client = new CmaClient(m_db);
usb_thread->setObjectName("usb_thread");
connect(usb_thread, SIGNAL(started()), client, SLOT(connectUsb()));
connect(client, SIGNAL(finished()), usb_thread, SLOT(quit()), Qt::DirectConnection);
connect(usb_thread, SIGNAL(finished()), usb_thread, SLOT(deleteLater()));
connect(usb_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
connect(usb_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
client->moveToThread(usb_thread);
usb_thread->start();
thread_count++;
}
if(!settings.value("disableWireless", false).toBool()) {
CmaBroadcast *broadcast = new CmaBroadcast(this);
wireless_thread = new QThread();
client = new CmaClient(m_db, broadcast);
wireless_thread->setObjectName("wireless_thread");
connect(wireless_thread, SIGNAL(started()), client, SLOT(connectWireless()));
connect(client, SIGNAL(finished()), wireless_thread, SLOT(quit()), Qt::DirectConnection);
connect(wireless_thread, SIGNAL(finished()), wireless_thread, SLOT(deleteLater()));
connect(wireless_thread, SIGNAL(finished()), this, SLOT(threadStopped()));
connect(wireless_thread, SIGNAL(finished()), client, SLOT(deleteLater()));
connect(client, SIGNAL(refreshDatabase()), this, SLOT(refreshDatabase()));
client->moveToThread(wireless_thread);
wireless_thread->start();
thread_count++;
}
if(thread_count == 0) {
qCritical("You must enable at least USB or Wireless monitoring");
}
}
void HeadlessManager::receiveMessage(QString message)
{
QTextStream(stdout) << message << endl;
}
void HeadlessManager::stop()
{
if(CmaClient::stop() < 0) {
QCoreApplication::quit();
}
}
void HeadlessManager::threadStopped()
{
mutex.lock();
if(--thread_count == 0) {
QCoreApplication::quit();
}
mutex.unlock();
}
void HeadlessManager::hupSignalHandler(int)
{
char a = 1;
::write(sighup_fd[0], &a, sizeof(a));
}
void HeadlessManager::termSignalHandler(int)
{
char a = 1;
::write(sigterm_fd[0], &a, sizeof(a));
}
void HeadlessManager::handleSigTerm()
{
sn_term->setEnabled(false);
char tmp;
::read(sigterm_fd[1], &tmp, sizeof(tmp));
stop();
sn_term->setEnabled(true);
}
void HeadlessManager::handleSigHup()
{
sn_hup->setEnabled(false);
char tmp;
::read(sighup_fd[1], &tmp, sizeof(tmp));
refreshDatabase();
sn_hup->setEnabled(true);
}

76
cli/headlessmanager.h Normal file
View File

@@ -0,0 +1,76 @@
/*
* QCMA: Cross-platform content manager assistant for the PS Vita
*
* Copyright (C) 2013 Codestation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HEADLESSMANAGER_H
#define HEADLESSMANAGER_H
#include "database.h"
#include <QObject>
#include <QThread>
#include <QSocketNotifier>
class HeadlessManager : public QObject
{
Q_OBJECT
public:
explicit HeadlessManager(QObject *parent = 0);
~HeadlessManager();
void start();
// unix signal handlers
static void hupSignalHandler(int);
static void termSignalHandler(int);
private:
int thread_count;
QMutex mutex;
Database *m_db;
QThread *usb_thread;
QThread *wireless_thread;
// signal handling
static int sighup_fd[2];
static int sigterm_fd[2];
QSocketNotifier *sn_hup;
QSocketNotifier *sn_term;
signals:
void stopped();
void databaseUpdated(int count);
public slots:
void refreshDatabase();
void stop();
// Qt signal handlers
void handleSigHup();
void handleSigTerm();
private slots:
void threadStopped();
void receiveMessage(QString message);
};
#endif // HEADLESSMANAGER_H

165
cli/main_cli.cpp Normal file
View File

@@ -0,0 +1,165 @@
/*
* QCMA: Cross-platform content manager assistant for the PS Vita
*
* Copyright (C) 2013 Codestation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef Q_OS_WIN32
#include <signal.h>
#endif
#include <QDebug>
#include <QLibraryInfo>
#include <QLocale>
#include <QStringList>
#include <QTextCodec>
#include <QThread>
#include <QTranslator>
#include <inttypes.h>
#include <vitamtp.h>
#include "singlecoreapplication.h"
#include "headlessmanager.h"
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
static void noDebugOutput(QtMsgType type, const QMessageLogContext &, const QString & msg)
{
QByteArray localMsg = msg.toLocal8Bit();
const char *message = localMsg.constData();
#else
static void noDebugOutput(QtMsgType type, const char *message)
{
#endif
switch (type) {
case QtDebugMsg:
break;
case QtWarningMsg:
fprintf(stderr, "Warning: %s\n", message);
break;
case QtCriticalMsg:
fprintf(stderr, "Critical: %s\n", message);
break;
case QtFatalMsg:
fprintf(stderr, "Fatal: %s\n", message);
abort();
}
}
static bool setup_handlers()
{
struct sigaction hup, term;
hup.sa_handler = HeadlessManager::hupSignalHandler;
sigemptyset(&hup.sa_mask);
hup.sa_flags = 0;
hup.sa_flags |= SA_RESTART;
if (sigaction(SIGHUP, &hup, NULL) != 0) {
qCritical("SIGHUP signal handle failed");
return false;
}
term.sa_handler = HeadlessManager::termSignalHandler;
sigemptyset(&term.sa_mask);
term.sa_flags |= SA_RESTART;
if (sigaction(SIGTERM, &term, NULL) != 0) {
qCritical("SIGTERM signal handle failed");
return false;
}
if (sigaction(SIGINT, &term, NULL) != 0) {
qCritical("SIGINT signal handle failed");
return false;
}
return true;
}
int main(int argc, char *argv[])
{
if(SingleCoreApplication::sendMessage("Another instance of Qcma tried to start")) {
QTextStream(stdout) << "An instance of Qcma is already running" << endl;
return 0;
}
SingleCoreApplication app(argc, argv);
// FIXME: libmtp sends SIGPIPE if a socket write fails crashing the whole app
// the proper fix is to libmtp to handle the cancel properly or ignoring
// SIGPIPE on the socket
signal(SIGPIPE, SIG_IGN);
if(!setup_handlers())
return 1;
if(app.arguments().contains("--with-debug")) {
VitaMTP_Set_Logging(VitaMTP_DEBUG);
} else if(app.arguments().contains("--verbose")) {
VitaMTP_Set_Logging(VitaMTP_VERBOSE);
} else {
VitaMTP_Set_Logging(VitaMTP_NONE);
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
qInstallMessageHandler(noDebugOutput);
#else
qInstallMsgHandler(noDebugOutput);
#endif
}
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
#endif
QTextStream(stdout) << "Starting Qcma " << QCMA_VER << endl;
QTranslator translator;
QString locale = QLocale().system().name();
qDebug() << "Current locale:" << locale;
if(app.arguments().contains("--set-locale")) {
int index = app.arguments().indexOf("--set-locale");
if(index + 1 < app.arguments().length()) {
qDebug("Enforcing locale: %s", app.arguments().at(index + 1).toUtf8().data());
locale = app.arguments().at(index + 1);
}
}
if(translator.load("qcma_" + locale, ":/resources/translations")) {
app.installTranslator(&translator);
} else {
qWarning() << "Cannot load translation for locale:" << locale;
}
QTranslator system_translator;
system_translator.load("qt_" + locale, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
app.installTranslator(&system_translator);
qDebug("Starting main thread: 0x%016" PRIxPTR, (uintptr_t)QThread::currentThreadId());
// set the organization/application for QSettings to work properly
app.setOrganizationName("codestation");
app.setApplicationName("qcma");
HeadlessManager manager;
// receive the message from another process
QObject::connect(&app, SIGNAL(messageAvailable(QString)), &manager, SLOT(receiveMessage(QString)));
manager.start();
return app.exec();
}

33
cli/qcma_cli.1 Normal file
View File

@@ -0,0 +1,33 @@
.TH QCMA-CLI 1 "MARCH 2015"
.SH NAME
qcma-cli \- Content manager for the PlayStation Vita
.SH SYNOPSIS
.B qcma_cli \fR[options]
.TP
.B \-\-verbose
print detailed output
.TP
.B \-\-with-debug
print very verbose output (including hexdump transfers)
.SH DESCRIPTION
\fBqcma_cli\fR is a cross-platform application to provide an Open Source implementation
of the original Content Manager Assistant that comes with the PS Vita.
.TP
Qcma will let you backup your games, songs, photos & videos via USB or wireless.
.SH SIGNALS
You can control \fBqcma_cli\fR using signals, i.e. using the \fBkill\fR command to send a signal to the process.
.TP
.B SIGHUP
Refreshes the database.
.TP
.B SIGTERM or SIGINT
Shuts down the process but waits until the current event is finished.
.SH "SEE ALSO"
.I /usr/share/doc/qcma/README.md

View File

@@ -0,0 +1,69 @@
/*
* QCMA: Cross-platform content manager assistant for the PS Vita
*
* Copyright (C) 2013 Codestation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "singlecoreapplication.h"
#include <QDebug>
const int SingleCoreApplication::timeout = 500;
const QString SingleCoreApplication::SHARED_KEY = "QCMA_KEY";
SingleCoreApplication::SingleCoreApplication(int &argc, char **argv) :
QCoreApplication(argc, argv)
{
server = new QLocalServer(this);
connect(server, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
QLocalServer::removeServer(SHARED_KEY);
server->listen(SHARED_KEY);
}
void SingleCoreApplication::receiveMessage()
{
QLocalSocket *socket = server->nextPendingConnection();
if(!socket->waitForReadyRead(timeout)) {
qDebug() << socket->errorString();
return;
}
QByteArray byteArray = socket->readAll();
QString message = QString::fromUtf8(byteArray.constData());
emit messageAvailable(message);
socket->disconnectFromServer();
}
bool SingleCoreApplication::sendMessage(const QString &message)
{
QLocalSocket socket;
socket.connectToServer(SHARED_KEY, QIODevice::WriteOnly);
if(!socket.waitForConnected(timeout)) {
return false;
}
socket.write(message.toUtf8());
if(!socket.waitForBytesWritten(timeout)) {
qDebug() << socket.errorString();
return false;
}
socket.disconnectFromServer();
return true;
}

View File

@@ -0,0 +1,50 @@
/*
* QCMA: Cross-platform content manager assistant for the PS Vita
*
* Copyright (C) 2013 Codestation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SINGLECOREAPPLICATION_H
#define SINGLECOREAPPLICATION_H
#include <QCoreApplication>
#include <QLocalSocket>
#include <QLocalServer>
#include <QSharedMemory>
class SingleCoreApplication : public QCoreApplication
{
Q_OBJECT
public:
explicit SingleCoreApplication(int &argc, char **argv);
static bool sendMessage(const QString &message);
private:
QLocalServer *server;
static const int timeout;
static const QString SHARED_KEY;
signals:
void messageAvailable(QString message);
public slots:
void receiveMessage();
};
#endif // SINGLECOREAPPLICATION_H