Answer the question
In order to leave comments, you need to log in
How to implement cross-platform software with libraries for Windows/Linux?
The software itself will be on QT, but so that ifdefs are not scattered around the code, I wanted to move the OS-dependent code into 2 libraries for Windows and Linux with a common interface (not a GUI, but an API). How to implement it correctly?
Create a library project in Qt Creator? Would it be possible to create a DLL for Windows this way?
UPD:
Project #1: Library for Linux
int MyFileWrite(int file, unsigned char *data, int lengh)
{
return write(file, data, lengh);
}
int MyFileWrite(int file, unsigned char *data, int lengh)
{
return fwrite (data, sizeof(char), lengh, file);
}
ifdef WINDOWS
// подключить библиотеку
elseif LINUX
// подключить библиотеку
endif
Answer the question
In order to leave comments, you need to log in
I have been improving the game framework since 2011. All of its code is written in C++. There used to be 5 target platforms (Win, MacOs, iOs, Android, Bada), now 4 (Bada closed) with an eye on Tizen, WinMo and, someday, consoles.
In general, the level of requirements for cross-platform should be clear. And here is how I achieved it.
Most of the code is written in platform-independent C++. All platform-specific code is split into three layers:
- Bottom layer, common interface for all platforms, common fields for all platforms.
- Middle layer, platform-specific solutions and fields. Inherited from the bottom.
- Top layer, injecting platform-specific code into the framework. Inherited from the middle layer.
Conditional compilation is used only to include the platform-specific code header. No macros, no conditional compilation is allowed anymore. In platform-specific code, everything is written in open source as if it were written for one platform.
At the file level, this approach works like this.
There is a "platform" folder in the project headers, where the lower levels of splitting are collected, the master header with a conditional connection of the middle splitting level and all common types for platforms.
Also in the project there are folders "platform.windows", "platform.macos", "platform.###" in which the middle level of splitting and master headers for conditional connection are implemented.
The top level is either implemented in its own folder, if it is a whole subsystem, or is described in the same "platform" folder.
The source code is grouped in the same way, but only includes the master header.
Build scripts for each of the platforms include platform-specific code only for their platform.
Everything is collected into static libraries and linked into one executable file. Although there is the possibility of crowding out libraries into dynamic modules (done in case the framework is transferred to outsourcers).
All this gives complete transparency of code execution for any platform. Also, this approach makes it very easy to expand the entire framework to a new platform.
The example with the file fits very well due to its simplicity, I can even write it out from memory from my framework, but I will still simplify something so as not to confuse or scare anyone.
// PlatformSpecificFile.Windows.h
class PlatformSpecificFile
{
// Platform-specific interface.
public:
inline ::HANDLE GetHandle() const { return m_handle; };
// Platform-independent interface, but platform-dependent implementation.
public:
// RAII.
PlatformSpecificFile() = delete;
PlatformSpecificFile(
const std::string& path,
const OpeningMode desired_mode,
const AccessOptions& desired_access,
const SharingOptions& desired_sharing
);
virtual ~PlatformSpecificFile();
void Close();
void Flush();
const size64_t GetSize() const;
const bool Resize( const size64_t new_size );
const size32_t Read( NotNull<uint8_t> buffer, const size32_t buffer_size ) const;
const size32_t Write( NotNull<const uint8_t> buffer, const size32_t buffer_size );
const size64_t Seek( const size64_t offset, const SeekOrientation orientation );
inline const bool IsValid() const { return IsHandleValid( m_handle ); };
private:
::HANDLE m_handle = INVALID_HANDLE_VALUE;
};
// PlatformSpecificFile.Android.h
class PlatformSpecificFile
{
// Platform-specific interface.
public:
inline int GetHandle() const { return m_handle; };
// Platform-independent interface, but platform-dependent implementation.
public:
// RAII.
PlatformSpecificFile() = delete;
PlatformSpecificFile(
const std::string& path,
const OpeningMode desired_mode,
const AccessOptions& desired_access,
const SharingOptions& desired_sharing
);
virtual ~PlatformSpecificFile();
void Close();
void Flush();
const size64_t GetSize() const;
const bool Resize( const size64_t new_size );
const size32_t Read( NotNull<uint8_t> buffer, const size32_t buffer_size ) const;
const size32_t Write( NotNull<const uint8_t> buffer, const size32_t buffer_size );
const size64_t Seek( const size64_t offset, const SeekOrientation orientation );
inline const bool IsValid() const { return m_handle >= 0; };
private:
int m_handle = -1;
};
// File.h
class File final : public PlatformSpecificFile
{
public:
using PlatformSpecificFile::PlatformSpecificFile;
const size64_t GetPosition() const; // Seek( 0, SeekOrientation::FromPosition );
const bool SetPosition( const size64_t position ); // Seek( position, SeekOrientation::FromBeginning );
const bool IsFileEnded() const; // GetPosition() == getSize();
};
How to implement it correctly?
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question