Support minimal dependency linux build.

This commit is contained in:
James Grogan 2022-11-10 09:06:02 +00:00
parent 92a35a5bc9
commit 7ce29ce8ae
14 changed files with 421 additions and 176 deletions

View file

@ -1,5 +1,39 @@
# limmto # MediaTool
limmto (Light Multi-Media Tool) is a free, low-dependency C++ library for working with digital media.
This is a collection of tools and apps for working with various media (Web, Desktop Publishing, Video/Audio) on different platforms (Linux, Windows).
It tries to have low dependencies and lots of things are built from scratch.
This is a personal/hobby project - things will break/change a lot.
# Build Dependencies
## Linux
### Minimal
```bash
sudo apt-get install build-essential cmake
```
### Optional
#### Audio
```bash
sudo apt-get install libasound2-dev
```
#### Image Formats
```bash
sudo apt-get install libpng-dev
```
# Build from Source
## Linux
```bash ```bash
mkdir build mkdir build

View file

@ -1,24 +1,9 @@
# Sample GUI # Sample GUI
add_executable(sample_gui gui-main.cpp)
target_include_directories(sample_gui PUBLIC add_subdirectory(sample-gui)
"${PROJECT_SOURCE_DIR}/src/console"
"${PROJECT_SOURCE_DIR}/src/client"
)
target_link_libraries(sample_gui PUBLIC client windows console core
network database geometry audio web)
if(WIN32) if(WIN32)
add_executable(sample_gui_win WIN32 gui-main-win.cpp) add_subdirectory(directx-practice)
target_include_directories(sample_gui PUBLIC
"${PROJECT_SOURCE_DIR}/src/console"
"${PROJECT_SOURCE_DIR}/src/client"
)
target_link_libraries(sample_gui_win PUBLIC client windows console core
network database geometry audio web)
set_property(TARGET sample_gui_win PROPERTY FOLDER apps)
add_subdirectory(directx-practice)
endif() endif()
# Sample Console # Sample Console
@ -30,7 +15,6 @@ target_link_libraries(sample_console PUBLIC console core network
database geometry audio web) database geometry audio web)
set_property(TARGET sample_console PROPERTY FOLDER apps) set_property(TARGET sample_console PROPERTY FOLDER apps)
set_property(TARGET sample_gui PROPERTY FOLDER apps)
add_subdirectory(website-generator) add_subdirectory(website-generator)

View file

@ -0,0 +1,27 @@
if(WIN32)
add_executable(sample_gui_win WIN32 gui-main-win.cpp)
target_include_directories(sample_gui PUBLIC
"${PROJECT_SOURCE_DIR}/src/console"
"${PROJECT_SOURCE_DIR}/src/client"
)
target_link_libraries(sample_gui_win PUBLIC client windows console core
network database geometry audio web)
set_property(TARGET sample_gui_win PROPERTY FOLDER apps)
else()
find_package(X11 QUIET)
if(X11_FOUND)
add_executable(sample_gui gui-main.cpp)
target_include_directories(sample_gui PUBLIC
"${PROJECT_SOURCE_DIR}/src/console"
"${PROJECT_SOURCE_DIR}/src/client"
)
target_link_libraries(sample_gui PUBLIC client windows console core
network database geometry audio web)
set_property(TARGET sample_gui PROPERTY FOLDER apps)
else()
message(STATUS "Skipping sample GUI as no X11 dev support")
endif()
endif()

View file

@ -50,8 +50,7 @@ void WebsiteGenerator::parseTemplateFiles()
const auto template_files = Directory::getFilesWithExtension(template_path, ".html"); const auto template_files = Directory::getFilesWithExtension(template_path, ".html");
for (const auto& path : template_files) for (const auto& path : template_files)
{ {
auto file = TemplateFile(path); mTemplateFiles[path.stem().string()] = std::make_unique<TemplateFile>(path);
mTemplateFiles[path.stem().string()] = file;
} }
} }

View file

@ -44,6 +44,7 @@ public:
{ {
} }
private: private:
Path mPath; Path mPath;
}; };
@ -80,5 +81,5 @@ private:
GeneratorConfig mConfig; GeneratorConfig mConfig;
std::vector<ContentPage> mPages; std::vector<ContentPage> mPages;
std::vector<ContentArticle> mArticles; std::vector<ContentArticle> mArticles;
std::unordered_map<std::string, TemplateFile> mTemplateFiles; std::unordered_map<std::string, std::unique_ptr<TemplateFile> > mTemplateFiles;
}; };

View file

@ -3,17 +3,26 @@ set(platform_HEADERS "")
set(platform_INCLUDES "") set(platform_INCLUDES "")
if (UNIX) if (UNIX)
find_package(ALSA REQUIRED) find_package(ALSA QUIET)
list(APPEND platform_HEADERS if(ALSA_FOUND)
audio_interfaces/AlsaInterface.h list(APPEND platform_HEADERS
${ALSA_INCLUDE_DIRS} audio_interfaces/AlsaInterface.h
) ${ALSA_INCLUDE_DIRS})
list(APPEND platform_INCLUDES list(APPEND platform_INCLUDES
audio_interfaces/AlsaInterface.cpp audio_interfaces/AlsaInterface.cpp
) )
list(APPEND platform_LIBS list(APPEND platform_LIBS
${ALSA_LIBRARIES} ${ALSA_LIBRARIES}
) )
else()
message(STATUS "ALSA package not found - not building audio interface.")
list(APPEND platform_HEADERS
audio_interfaces/NullAudioInterface.h
)
list(APPEND platform_INCLUDES
audio_interfaces/NullAudioInterface.cpp
)
endif()
else() else()
list(APPEND platform_HEADERS list(APPEND platform_HEADERS
audio_interfaces/WasapiInterface.h audio_interfaces/WasapiInterface.h

View file

@ -0,0 +1,141 @@
#include "AlsaInterface.h"
#include "FileLogger.h"
#include "AudioSynth.h"
#include <vector>
AlsaInterface::AlsaInterface()
:mHandle(),
mHardwareParams(),
mPeriodSize(8192)
{
}
AlsaInterface::~AlsaInterface()
{
}
std::unique_ptr<AlsaInterface> AlsaInterface::Create()
{
return std::make_unique<AlsaInterface>();
}
void AlsaInterface::OpenDevice(const AudioDevicePtr& device)
{
MLOG_INFO("Opening Device");
snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
if (snd_pcm_open(&mHandle, device->GetName().c_str(), stream, 0) < 0)
{
MLOG_ERROR("Error opening PCM device: " + device->GetName());
return;
}
snd_pcm_hw_params_alloca(&mHardwareParams);
if (snd_pcm_hw_params_any(mHandle, mHardwareParams) < 0)
{
MLOG_ERROR("Can not configure this PCM device.");
return;
}
SetAccessType(device);
SetSampleFormat(device);
SetSampleRate(device);
SetPeriod(device);
SetBufferSize(device);
SetChannelNumber(device);
/* Apply HW parameter settings to */
/* PCM device and prepare device */
if (snd_pcm_hw_params(mHandle, mHardwareParams) < 0) {
MLOG_ERROR("Error setting HW params.");
return;
}
}
void AlsaInterface::SetAccessType(const AudioDevicePtr& device)
{
if (snd_pcm_hw_params_set_access(mHandle, mHardwareParams, SND_PCM_ACCESS_RW_INTERLEAVED) < 0) {
MLOG_ERROR("Error setting device access.");
return;
}
}
void AlsaInterface::SetSampleFormat(const AudioDevicePtr& device)
{
/* Set sample format */
if (snd_pcm_hw_params_set_format(mHandle, mHardwareParams, SND_PCM_FORMAT_S16_LE) < 0) {
MLOG_ERROR("Error setting format. ");
return;
}
}
void AlsaInterface::SetSampleRate(const AudioDevicePtr& device)
{
unsigned rate = device->GetSampleRate();
unsigned exact_rate = rate;
if (snd_pcm_hw_params_set_rate_near(mHandle, mHardwareParams, &exact_rate, 0) < 0)
{
MLOG_ERROR("Error setting rate. ");
return;
}
if (rate != exact_rate) {
MLOG_ERROR("The rate is not supported by your hardware.");
}
}
void AlsaInterface::SetPeriod(const AudioDevicePtr& device)
{
/* Set number of periods. Periods used to be called fragments. */
if (snd_pcm_hw_params_set_periods(mHandle, mHardwareParams, device->GetPeriod(), 0) < 0)
{
MLOG_ERROR("Error setting periods. ");
return;
}
}
void AlsaInterface::SetBufferSize(const AudioDevicePtr& device)
{
int periods = static_cast<int>(device->GetPeriod());
/* Set buffer size (in frames). The resulting latency is given by */
/* latency = periodsize * periods / (rate * bytes_per_frame) */
if (snd_pcm_hw_params_set_buffer_size(mHandle, mHardwareParams, (mPeriodSize * periods)>>2) < 0)
{
MLOG_ERROR("Error setting buffersize. ");
return;
}
}
void AlsaInterface::SetChannelNumber(const AudioDevicePtr& device)
{
/* Set number of channels */
if (snd_pcm_hw_params_set_channels(mHandle, mHardwareParams, device->GetNumChannels()) < 0)
{
MLOG_ERROR("Error setting channels");
return;
}
}
void AlsaInterface::Play(const AudioDevicePtr& device)
{
MLOG_INFO("Playing audio");
AudioSynth synth;
const unsigned duration = 100;
double freq = 440;
auto data = synth.GetSineWave(freq, duration)->GetChannelData(0);
int numFrames = mPeriodSize >> 2;
for(int count = 0; count < duration; count++)
{
const auto offset= count*4*numFrames;
unsigned char frame[4] = {data[offset], data[offset+1], data[offset+2], data[offset+3]};
while ((snd_pcm_writei(mHandle, frame, numFrames)) < 0)
{
snd_pcm_prepare(mHandle);
MLOG_ERROR("<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>");
}
}
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "IAudioInterface.h"
#include "AudioDevice.h"
#include <memory>
#include <alsa/asoundlib.h>
class AlsaInterface : public IAudioInterface
{
snd_pcm_t* mHandle;
snd_pcm_hw_params_t* mHardwareParams;
snd_pcm_uframes_t mPeriodSize;
public:
AlsaInterface();
~AlsaInterface();
static std::unique_ptr<AlsaInterface> Create();
void OpenDevice(const AudioDevicePtr& device) override;
void SetAccessType(const AudioDevicePtr& device);
void SetSampleFormat(const AudioDevicePtr& device);
void SetSampleRate(const AudioDevicePtr& device);
void SetPeriod(const AudioDevicePtr& device);
void SetBufferSize(const AudioDevicePtr& device);
void SetChannelNumber(const AudioDevicePtr& device);
void Play(const AudioDevicePtr& device) override;
};
using AlsaInterfacePtr = std::shared_ptr<AlsaInterface>;

View file

@ -2,151 +2,152 @@
#include <iostream> #include <iostream>
#include <locale> #include <locale>
#include <algorithm>
TomlTable::TomlTable(const std::string& header) TomlTable::TomlTable(const std::string& header)
: mHeader(header) : mHeader(header)
{ {
} }
void TomlTable::addComment(const Comment& comment) void TomlTable::addComment(const Comment& comment)
{ {
mComments.push_back(comment); mComments.push_back(comment);
} }
void TomlTable::addTable(std::unique_ptr<TomlTable> table) void TomlTable::addTable(std::unique_ptr<TomlTable> table)
{ {
mTables[table->getHeader()] = std::move(table); mTables[table->getHeader()] = std::move(table);
} }
void TomlTable::addKeyValuePair(const std::string& key, const std::string& value) void TomlTable::addKeyValuePair(const std::string& key, const std::string& value)
{ {
mMap[key] = value; mMap[key] = value;
} }
std::string TomlTable::getHeader() const std::string TomlTable::getHeader() const
{ {
return mHeader; return mHeader;
} }
TomlTable* TomlTable::getTable(const std::string& path) TomlTable* TomlTable::getTable(const std::string& path)
{ {
return mTables[path].get(); return mTables[path].get();
} }
TomlTable::KeyValuePairs TomlTable::getKeyValuePairs() const TomlTable::KeyValuePairs TomlTable::getKeyValuePairs() const
{ {
return mMap; return mMap;
} }
TomlContent::TomlContent() TomlContent::TomlContent()
: mRootTable(std::make_unique<TomlTable>("root")) : mRootTable(std::make_unique<TomlTable>("root"))
{ {
} }
TomlTable* TomlContent::getRootTable() const TomlTable* TomlContent::getRootTable() const
{ {
return mRootTable.get(); return mRootTable.get();
} }
TomlTable* TomlContent::getTable(const std::string& path) const TomlTable* TomlContent::getTable(const std::string& path) const
{ {
return mRootTable->getTable(path); return mRootTable->getTable(path);
} }
TomlReader::TomlReader() TomlReader::TomlReader()
: mContent(std::make_unique<TomlContent>()) : mContent(std::make_unique<TomlContent>())
{ {
} }
TomlContent* TomlReader::getContent() const TomlContent* TomlReader::getContent() const
{ {
return mContent.get(); return mContent.get();
} }
void TomlReader::read(const Path& input_path) void TomlReader::read(const Path& input_path)
{ {
const auto lines = File(input_path).readLines(); const auto lines = File(input_path).readLines();
mLastSectionOffset = 0; mLastSectionOffset = 0;
mWorkingTable = mContent->getRootTable(); mWorkingTable = mContent->getRootTable();
for (const auto& line : lines) for (const auto& line : lines)
{ {
processLine(line); processLine(line);
mLastSectionOffset++; mLastSectionOffset++;
} }
mWorkingTable = nullptr; mWorkingTable = nullptr;
} }
void TomlReader::processLine(const std::string& line) void TomlReader::processLine(const std::string& line)
{ {
bool in_comment{ false }; bool in_comment{ false };
bool in_header{ false }; bool in_header{ false };
bool found_key{ false }; bool found_key{ false };
std::string working_string; std::string working_string;
std::string key_string; std::string key_string;
for (auto c : line) for (auto c : line)
{ {
if (c == '#' && !in_comment) if (c == '#' && !in_comment)
{ {
in_comment = true; in_comment = true;
} }
else if (c == '[' && !in_comment && !in_header) else if (c == '[' && !in_comment && !in_header)
{ {
in_header = true; in_header = true;
} }
else if (c == '=' && !in_comment && !in_header) else if (c == '=' && !in_comment && !in_header)
{ {
found_key = true; found_key = true;
key_string = working_string; key_string = working_string;
working_string = ""; working_string = "";
} }
else if (c == ']' && in_header) else if (c == ']' && in_header)
{ {
break; break;
} }
else else
{ {
working_string += c; working_string += c;
} }
} }
if (in_comment) if (in_comment)
{ {
mWorkingTable->addComment({ mLastSectionOffset, working_string }); mWorkingTable->addComment({ mLastSectionOffset, working_string });
} }
else if (in_header) else if (in_header)
{ {
onHeader(working_string); onHeader(working_string);
} }
else if (found_key) else if (found_key)
{ {
std::locale locale; std::locale locale;
key_string.erase(std::remove_if(key_string.begin(), key_string.end(), [locale](unsigned char c) {return std::isspace(c, locale); }), key_string.end()); key_string.erase(std::remove_if(key_string.begin(), key_string.end(), [locale](unsigned char c) {return std::isspace(c, locale); }), key_string.end());
working_string.erase(std::remove_if(working_string.begin(), working_string.end(), [locale](unsigned char c) {return std::isspace(c, locale); }), working_string.end()); working_string.erase(std::remove_if(working_string.begin(), working_string.end(), [locale](unsigned char c) {return std::isspace(c, locale); }), working_string.end());
if (working_string.size()>2 && working_string[0] == '"' && working_string[working_string.size() - 1] == '"') if (working_string.size()>2 && working_string[0] == '"' && working_string[working_string.size() - 1] == '"')
{ {
working_string = working_string.substr(1, working_string.size() - 2); working_string = working_string.substr(1, working_string.size() - 2);
} }
onKeyValuePair(key_string, working_string); onKeyValuePair(key_string, working_string);
} }
} }
void TomlReader::onHeader(const std::string& header) void TomlReader::onHeader(const std::string& header)
{ {
auto new_table = std::make_unique<TomlTable>(header); auto new_table = std::make_unique<TomlTable>(header);
auto table_temp = new_table.get(); auto table_temp = new_table.get();
mWorkingTable->addTable(std::move(new_table)); mWorkingTable->addTable(std::move(new_table));
mWorkingTable = table_temp; mWorkingTable = table_temp;
} }
void TomlReader::onKeyValuePair(const std::string key, const std::string value) void TomlReader::onKeyValuePair(const std::string key, const std::string value)
{ {
mWorkingTable->addKeyValuePair(key, value); mWorkingTable->addKeyValuePair(key, value);
} }

View file

@ -3,32 +3,29 @@ set(platform_INCLUDE_DIRS "")
set(platform_HEADERS "") set(platform_HEADERS "")
set(platform_LIBS "") set(platform_LIBS "")
if (UNIX)
list(APPEND platform_LIBSs
GL
)
else()
list(APPEND platform_LIBS
OpenGL32.lib
)
endif()
list(APPEND graphics_LIB_INCLUDES list(APPEND graphics_LIB_INCLUDES
DrawingContext.cpp DrawingContext.cpp
DrawingManager.cpp DrawingManager.cpp
DrawingSurface.cpp DrawingSurface.cpp
Rasterizer.cpp Rasterizer.cpp
opengl/OpenGlInterface.cpp ${platform_LIB_INCLUDES}
${platform_LIB_INCLUDES}
) )
list(APPEND graphics_HEADERS list(APPEND graphics_HEADERS
opengl/OpenGlInterface.h
${platform_HEADERS} ${platform_HEADERS}
Rasterizer.h Rasterizer.h
INativeDrawingSurface.h INativeDrawingSurface.h
INativeDrawingContext.h) INativeDrawingContext.h
)
find_package(OpenGL QUIET)
if (OpenGL_FOUND)
list(APPEND platform_LIBS OpenGL::GL)
list(APPEND graphics_LIB_INCLUDES opengl/OpenGlInterface.cpp)
list(APPEND graphics_HEADERS opengl/OpenGlInterface.h)
else()
message(STATUS "OpenGL headers not found - skipping OpenGL support")
endif()
add_library(graphics SHARED add_library(graphics SHARED
${graphics_LIB_INCLUDES} ${graphics_LIB_INCLUDES}

View file

@ -4,50 +4,51 @@ set (platform_LIBS "")
set(_HAS_WAYLAND Off) set(_HAS_WAYLAND Off)
if(UNIX) if(UNIX)
list(APPEND platform_INCLUDES find_package(X11 QUIET)
ui_interfaces/x11/XcbInterface.cpp if(X11_FOUND)
ui_interfaces/x11/XcbEventInterface.cpp list(APPEND platform_INCLUDES
ui_interfaces/x11/XcbWindow.cpp ui_interfaces/x11/XcbInterface.cpp
ui_interfaces/x11/XcbScreen.cpp ui_interfaces/x11/XcbEventInterface.cpp
ui_interfaces/x11/XcbWindowInterface.cpp ui_interfaces/x11/XcbWindow.cpp
ui_interfaces/x11/XcbLayerInterface.cpp ui_interfaces/x11/XcbScreen.cpp
ui_interfaces/x11/XcbTextInterface.cpp ui_interfaces/x11/XcbWindowInterface.cpp
ui_interfaces/x11/XcbKeyboard.cpp ui_interfaces/x11/XcbLayerInterface.cpp
ui_interfaces/x11/GlxInterface.cpp ui_interfaces/x11/XcbTextInterface.cpp
ui_interfaces/x11/XcbKeyboard.cpp
ui_interfaces/x11/GlxInterface.cpp
)
list(APPEND platform_LIBS ${X11_LIBRARIES} ${X11_xcb_LIB} ${X11_X11_xcb_LIB})
else()
message(STATUS "x11 development headers not found - skipping support")
endif()
find_path(WAYLAND_CLIENT_INCLUDE_DIR NAMES wayland-client.h)
if (NOT ${WAYLAND_CLIENT_INCLUDE_DIR-NOTFOUND})
list(APPEND WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIR})
find_path(WAYLAND_EXTENSIONS_INCLUDE_DIR NAMES xdg-shell-client-protocol.h
HINTS ENV WAYLAND_EXTENSION_DIR
) )
if(NOT ${WAYLAND_EXTENSIONS_INCLUDE_DIR-NOTFOUND})
find_library(
WAYLAND_CLIENT_LIBRARY
NAMES wayland-client libwayland-client
)
list(APPEND platform_LIBS list(APPEND WAYLAND_INCLUDE_DIRS ${WAYLAND_EXTENSIONS_INCLUDE_DIR})
X11 X11-xcb xcb )
list(APPEND platform_INCLUDES
find_path( ui_interfaces/wayland/WaylandWindowInterface.cpp
WAYLAND_CLIENT_INCLUDE_DIR ui_interfaces/wayland/WaylandSurface.cpp
NAMES wayland-client.h ui_interfaces/wayland/WaylandBuffer.cpp
) ${WAYLAND_EXTENSIONS_INCLUDE_DIR}/xdg-shell-protocol.cpp
list(APPEND WAYLAND_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIR}) )
set(_HAS_WAYLAND ON)
find_path( else()
WAYLAND_EXTENSIONS_INCLUDE_DIR message(STATUS "Wayland Extensions Header not found - not building Wayland support")
NAMES xdg-shell-client-protocol.h endif()
HINTS ENV WAYLAND_EXTENSION_DIR
)
if(NOT ${WAYLAND_EXTENSIONS_INCLUDE_DIR-NOTFOUND})
find_library(
WAYLAND_CLIENT_LIBRARY
NAMES wayland-client libwayland-client
)
list(APPEND WAYLAND_INCLUDE_DIRS ${WAYLAND_EXTENSIONS_INCLUDE_DIR})
list(APPEND platform_INCLUDES
ui_interfaces/wayland/WaylandWindowInterface.cpp
ui_interfaces/wayland/WaylandSurface.cpp
ui_interfaces/wayland/WaylandBuffer.cpp
${WAYLAND_EXTENSIONS_INCLUDE_DIR}/xdg-shell-protocol.cpp
)
set(_HAS_WAYLAND ON)
else() else()
message(STATUS "Wayland Extensions Header not found - not building Wayland support") message(STATUS "Wayland Client Header not found - not building Wayland support")
endif() endif()
else() else()

View file

@ -11,15 +11,13 @@ list(APPEND TestFiles
audio/TestAudioWriter.cpp audio/TestAudioWriter.cpp
audio/TestMidiReader.cpp audio/TestMidiReader.cpp
core/TestBinaryStream.cpp core/TestBinaryStream.cpp
core/TestTomlReader.cpp core/TestTomlReader.cpp
compiler/TestLexer.cpp compiler/TestLexer.cpp
compiler/TestTemplatingEngine.cpp compiler/TestTemplatingEngine.cpp
compression/TestStreamCompressor.cpp compression/TestStreamCompressor.cpp
database/TestDatabase.cpp database/TestDatabase.cpp
fonts/TestFontReader.cpp fonts/TestFontReader.cpp
graphics/TestOpenGlRendering.cpp
graphics/TestRasterizer.cpp graphics/TestRasterizer.cpp
ipc/TestDbus.cpp
image/TestPngReader.cpp image/TestPngReader.cpp
image/TestPngWriter.cpp image/TestPngWriter.cpp
network/TestNetworkManagerClient.cpp network/TestNetworkManagerClient.cpp
@ -30,20 +28,33 @@ list(APPEND TestFiles
if (${HAS_FFMPEG}) if (${HAS_FFMPEG})
list(APPEND TestFiles list(APPEND TestFiles
video/TestVideoDecoder.cpp video/TestVideoDecoder.cpp
) )
endif() endif()
if (${HAS_WAYLAND}) if (${HAS_WAYLAND})
list(APPEND TestFiles list(APPEND TestFiles
windows/TestWaylandWindow.cpp windows/TestWaylandWindow.cpp
) )
endif() endif()
find_package(OpenGL QUIET)
if (OpenGL_FOUND)
list(APPEND TestFiles
graphics/TestOpenGlRendering.cpp
)
endif()
find_package(PkgConfig) find_package(PkgConfig)
pkg_check_modules(DBUS dbus-1) pkg_check_modules(DBUS dbus-1)
include_directories(${DBUS_INCLUDE_DIRS}) if (DBUS_FOUND)
link_directories(${DBUS_LIBRARY_DIRS}) include_directories(${DBUS_INCLUDE_DIRS})
link_directories(${DBUS_LIBRARY_DIRS})
list(APPEND TestFiles
ipc/TestDbus.cpp
)
endif()
foreach(TestFile ${TestFiles}) foreach(TestFile ${TestFiles})
cmake_path(GET TestFile FILENAME TestFileName) cmake_path(GET TestFile FILENAME TestFileName)