Skip to content
96 changes: 60 additions & 36 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ endif()

option(INSTALL_SYSTEMD_UNITS "Install TigerVNC systemd units" ON)

if(MSVC)
message(FATAL_ERROR "TigerVNC cannot be built with Visual Studio. Please use MinGW")
if(MSVC AND NOT ALLOW_MSVC_EXPERIMENTAL)
message(FATAL_ERROR "TigerVNC cannot be built with Visual Studio. Please use MinGW (or pass -DALLOW_MSVC_EXPERIMENTAL=ON to try anyway)")
endif()

if(NOT BUILD_TIMESTAMP)
Expand Down Expand Up @@ -67,27 +67,40 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -D_DEBUG")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG")

# Enable debug friendly optimizations for debug builds
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")

# Make sure we get a sane C and C++ version
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

# Tell the compiler to be stringent
add_compile_definitions(_FORTIFY_SOURCE=2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
# Make sure we catch these issues whilst developing
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror")
# clang doesn't support format_arg, which breaks this warning
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-nonliteral -Wno-format-security")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
# (GCC/Clang-only spelling; MSVC's own /RTC1 default conflicts with it — see
# "D8016: '/RTC1' and '/Og' command-line options are incompatible")
if(NOT MSVC)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Og")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og")
else()
# cl.exe rejects every GNU spelling above, so MSVC would otherwise get
# no standard flag at all and fall back to its default -- which is too
# old for the inline variables in SSecurityRSAAES.cxx.
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++17")
endif()

# These are GCC/Clang-only flag spellings; MSVC's cl.exe rejects them outright
# (e.g. "D8021: invalid numeric argument '/Wextra'"), so keep the whole GNU-style
# stringency stanza out of MSVC builds and rely on CMake's own MSVC defaults.
if(NOT MSVC)
# Make sure we get a sane C and C++ version
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
# Tell the compiler to be stringent
add_compile_definitions(_FORTIFY_SOURCE=2)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra -Wformat=2 -Wvla")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wzero-as-null-pointer-constant")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wshadow")
# Make sure we catch these issues whilst developing
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Werror")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Werror")
# clang doesn't support format_arg, which breaks this warning
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-format-nonliteral -Wno-format-security")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-format-nonliteral -Wno-format-security")
endif()
endif()

option(ENABLE_ASAN "Enable address sanitizer support" OFF)
Expand All @@ -103,8 +116,12 @@ if(ENABLE_TSAN AND NOT WIN32 AND NOT APPLE AND CMAKE_SIZEOF_VOID_P MATCHES 8)
endif()

if(MSVC)
# undef min and max macro
target_compile_definitions(rfb PRIVATE NOMINMAX)
# undef min and max macro -- global, not per-target: the "rfb" target
# doesn't exist yet at this point in the file (add_subdirectory(common)
# runs later), so target_compile_definitions(rfb ...) here always failed;
# this MSVC branch was untestable before the hard MSVC gate above was
# relaxed, so the ordering bug was never caught.
add_compile_definitions(NOMINMAX)
endif()

if(NOT DEFINED BUILD_WINVNC)
Expand All @@ -121,6 +138,12 @@ endif()
# Minimum version is Windows 7
if(WIN32)
add_definitions(-D_WIN32_WINNT=0x0601)
# Without this, <windows.h> pulls in the legacy <winsock.h>, which then
# conflicts with <winsock2.h> wherever both end up included in the same
# translation unit regardless of include order (duplicate struct/function
# definitions with "different linkage"). MinGW builds never hit this since
# mingw's own <windows.h> already defines this by default.
add_definitions(-DWIN32_LEAN_AND_MEAN)
endif()

# Legacy macros (macOS 10.12 and older) conflict with our code
Expand Down Expand Up @@ -185,10 +208,6 @@ trioption(ENABLE_H264 "Enable H.264 RFB encoding")
if(ENABLE_H264)
if(WIN32)
set(HAVE_H264 1)

set(CMAKE_REQUIRED_LIBRARIES ole32 mfplat mfuuid wmcodecdspuuid)
check_variable_exists(CLSID_VideoProcessorMFT HAVE_VIDEO_PROCESSOR_MFT)
set(CMAKE_REQUIRED_LIBRARIES)
else()
if(ENABLE_H264 STREQUAL "AUTO")
find_package(AVCodec)
Expand Down Expand Up @@ -289,7 +308,9 @@ if(BUILD_VIEWER)
endif()

if(FLTK_FOUND)
set(CMAKE_REQUIRED_FLAGS "-Wno-error")
if(NOT MSVC)
set(CMAKE_REQUIRED_FLAGS "-Wno-error")
endif()
set(CMAKE_REQUIRED_INCLUDES ${FLTK_INCLUDE_DIR})
set(CMAKE_REQUIRED_LIBRARIES ${FLTK_LIBRARIES})

Expand Down Expand Up @@ -439,12 +460,15 @@ include(cmake/StaticBuild.cmake)

add_subdirectory(common)

if(WIN32)
add_subdirectory(win)
else()
# No interest in building x related parts on Apple
if(NOT APPLE)
add_subdirectory(unix)
option(BUILD_SERVER "Build the platform-specific VNC server components" ON)
if(BUILD_SERVER)
if(WIN32)
add_subdirectory(win)
else()
# No interest in building x related parts on Apple
if(NOT APPLE)
add_subdirectory(unix)
endif()
endif()
endif()

Expand Down
1 change: 1 addition & 0 deletions common/core/Configuration.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <core/Configuration.h>
#include <core/LogWriter.h>
#include <core/i18n.h>
#include <core/os.h>
#include <core/string.h>

#include <rdr/HexOutStream.h>
Expand Down
1 change: 1 addition & 0 deletions common/core/LogWriter.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <string.h>

#include <core/Configuration.h>
#include <core/os.h>
#include <core/LogWriter.h>
#include <core/i18n.h>
#include <core/string.h>
Expand Down
7 changes: 4 additions & 3 deletions common/core/LogWriter.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,21 @@

#include <core/Configuration.h>
#include <core/Logger.h>
#include <core/compiler.h>

// Each log writer instance has a unique textual name,
// and is attached to a particular Log instance and
// is assigned a particular log level.

#define DEF_LOGFUNCTION(name, level) \
inline void v##name(const char* fmt, va_list ap) \
__attribute__((__format__ (__printf__, 2, 0))) \
CORE_FORMAT_PRINTF(2, 0) \
{ \
if (m_log && (level <= m_level)) \
m_log->write(level, m_name, fmt, ap); \
} \
inline void name(const char* fmt, ...) \
__attribute__((__format__ (__printf__, 2, 3))) \
CORE_FORMAT_PRINTF(2, 3) \
{ \
if (m_log && (level <= m_level)) { \
va_list ap; va_start(ap, fmt); \
Expand All @@ -61,7 +62,7 @@ namespace core {
int getLevel(void) { return m_level; }

inline void write(int level, const char* format, ...)
__attribute__((__format__ (__printf__, 3, 4)))
CORE_FORMAT_PRINTF(3, 4)
{
if (m_log && (level <= m_level)) {
va_list ap;
Expand Down
1 change: 1 addition & 0 deletions common/core/Logger.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <stdio.h>
#include <string.h>

#include <core/os.h>
#include <core/Logger.h>
#include <core/LogWriter.h>
#include <core/i18n.h>
Expand Down
4 changes: 3 additions & 1 deletion common/core/Logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include <stdarg.h>
#include <stdio.h>

#include <core/compiler.h>

// Each log writer instance has a unique textual name,
// and is attached to a particular Logger instance and
// is assigned a particular log level.
Expand All @@ -46,7 +48,7 @@ namespace core {

virtual void write(int level, const char *logname, const char *text) = 0;
void write(int level, const char *logname, const char* format, va_list ap)
__attribute__((__format__ (__printf__, 4, 0)));
CORE_FORMAT_PRINTF(4, 0);

// -=- Register a logger

Expand Down
1 change: 1 addition & 0 deletions common/core/Logger_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <limits.h>

#include <core/Logger.h>
#include <core/os.h>

namespace core {

Expand Down
14 changes: 8 additions & 6 deletions common/core/Rect.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

#include <algorithm>

#include <core/compiler.h>

namespace core {

// core::Point
Expand All @@ -38,15 +40,15 @@ namespace core {
Point() : x(0), y(0) {}
Point(int x_, int y_) : x(x_), y(y_) {}
inline Point negate() const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{return Point(-x, -y);}
inline bool operator==(const Point &p) const {return x==p.x && y==p.y;}
inline bool operator!=(const Point &p) const {return x!=p.x || y!=p.y;}
inline Point translate(const Point &p) const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{return Point(x+p.x, y+p.y);}
inline Point subtract(const Point &p) const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{return Point(x-p.x, y-p.y);}
int x, y;
};
Expand All @@ -70,7 +72,7 @@ namespace core {
tl.x = x; tl.y = y; br.x = x+w; br.y = y+h;
}
inline Rect intersect(const Rect &r) const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{
Rect result;
result.tl.x = std::max(tl.x, r.tl.x);
Expand All @@ -80,7 +82,7 @@ namespace core {
return result;
}
inline Rect union_boundary(const Rect &r) const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{
if (r.is_empty()) return *this;
if (is_empty()) return r;
Expand All @@ -92,7 +94,7 @@ namespace core {
return result;
}
inline Rect translate(const Point &p) const
__attribute__ ((warn_unused_result))
CORE_WARN_UNUSED_RESULT
{
return Rect(tl.translate(p), br.translate(p));
}
Expand Down
7 changes: 4 additions & 3 deletions common/core/Region.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <vector>

#include <core/Rect.h>
#include <core/compiler.h>

struct pixman_region16;

Expand Down Expand Up @@ -58,11 +59,11 @@ namespace core {
// the following three operations return a new region:

Region intersect(const Region& r) const
__attribute__ ((warn_unused_result));
CORE_WARN_UNUSED_RESULT;
Region union_(const Region& r) const
__attribute__ ((warn_unused_result));
CORE_WARN_UNUSED_RESULT;
Region subtract(const Region& r) const
__attribute__ ((warn_unused_result));
CORE_WARN_UNUSED_RESULT;

bool operator==(const Region& b) const;
bool operator!=(const Region& b) const;
Expand Down
5 changes: 5 additions & 0 deletions common/core/Timer.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@
#endif

#include <stdio.h>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/time.h>
#endif

#include <algorithm>

#include <core/LogWriter.h>
#include <core/Timer.h>
#include <core/os.h>
#include <core/time.h>

using namespace core;
Expand Down
4 changes: 4 additions & 0 deletions common/core/Timer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@
#define __CORE_TIMER_H__

#include <list>
#ifdef _WIN32
#include <winsock2.h>
#else
#include <sys/time.h>
#endif

namespace core {

Expand Down
37 changes: 37 additions & 0 deletions common/core/compiler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* Copyright 2026 jose-pr <jose-pr@coqui.dev>
*
* This 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 2 of the License, or
* (at your option) any later version.
*
* This software 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 software; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
* USA.
*/

#ifndef __CORE_COMPILER_H__
#define __CORE_COMPILER_H__

/*
* A handful of GCC/Clang-only attributes have no MSVC equivalent; these
* macros expand to the attribute where supported and to nothing otherwise.
*/
#if defined(__GNUC__) || defined(__clang__)
#define CORE_FORMAT_PRINTF(fmt_idx, args_idx) \
__attribute__((__format__ (__printf__, fmt_idx, args_idx)))
#define CORE_FORMAT_ARG(idx) __attribute__ ((format_arg (idx)))
#define CORE_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
#else
#define CORE_FORMAT_PRINTF(fmt_idx, args_idx)
#define CORE_FORMAT_ARG(idx)
#define CORE_WARN_UNUSED_RESULT
#endif

#endif // __CORE_COMPILER_H__
Loading