-
Notifications
You must be signed in to change notification settings - Fork 193
OW tools usage with VSCode
Install Open Watcom V2 with the DOS target operating system. The compiler does not need to be on the system PATH — the CMake presets below handle all environment setup.
| Host OS | Example install path | Compiler binaries |
|---|---|---|
| Windows | C:\WATCOM |
binnt64\ (64-bit host) or binnt\ (32-bit host) |
| Linux | /opt/watcom |
binl64/ (64-bit host) or binl/ (32-bit host) |
Note: The paths above are examples. Adjust the
WATCOMenvironment variable inCMakePresets.jsonandc_cpp_properties.jsonto match your actual install location.
Install Visual Studio Code with these extensions:
-
C/C++ Extension Pack (
ms-vscode.cpptools-extension-pack) — includes C/C++ IntelliSense, CMake Tools, and CMake language support -
CMake Language Support (
twxs.cmake) — syntax highlighting for CMakeLists.txt
Tip: Add an
.vscode/extensions.jsonto your project so VS Code prompts collaborators to install the required extensions automatically:{ "recommendations": [ "ms-vscode.cpptools-extension-pack", "twxs.cmake" ] }
Requires CMake 3.21+ (for preset condition support and the Watcom WMake generator).
my-project/
├── .vscode/
│ ├── c_cpp_properties.json ← IntelliSense configuration
│ ├── extensions.json ← recommended extensions
│ └── settings.json ← CMake Tools settings
├── include/
│ └── myheader.h
├── src/
│ └── main.c
├── CMakeLists.txt
└── CMakePresets.json ← replaces user-local CMake Kits
Instead of editing the user-local cmake-tools-kits.json, create a CMakePresets.json in the project root. This is portable (committed to version control), cross-platform (Linux and Windows), and requires no per-user setup.
The presets are organized in a hierarchy:
default (shared binaryDir)
├── dos-host-linux (Linux paths/env, hidden)
├── dos-host-windows (Windows paths/env, hidden)
└── dos-base (inherits both host presets; generator, common cache vars)
├── dos32-base (wcl386 compiler, hidden)
│ ├── dos32-debug
│ └── dos32-release
└── dos16-base (wcl compiler, I86 processor, hidden)
├── dos16-debug
└── dos16-release
Only presets without "hidden": true appear in VS Code's preset picker.
{
"version": 6,
"configurePresets": [
{
"name": "default",
"hidden": true,
"binaryDir": "${sourceDir}/build"
},
{
"name": "dos-host-linux",
"hidden": true,
"inherits": "default",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
},
"environment": {
"WATCOM": "/opt/watcom",
"WATCOM_BINDIR": "$env{WATCOM}/binl64",
"PATH": "$env{WATCOM}/binl64:$env{WATCOM}/binl:$penv{PATH}"
}
},
{
"name": "dos-host-windows",
"hidden": true,
"inherits": "default",
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
},
"environment": {
"WATCOM": "C:/WATCOM",
"WATCOM_BINDIR": "$env{WATCOM}/binnt64",
"Path": "$env{WATCOM}/binnt64;$env{WATCOM}/binnt;$penv{Path}"
}
},
{
"name": "dos-base",
"hidden": true,
"inherits": ["dos-host-linux", "dos-host-windows"],
"generator": "Watcom WMake",
"environment": {
"EDPATH": "$env{WATCOM}/eddat",
"INCLUDE": "$env{WATCOM}/h"
},
"cacheVariables": {
"CMAKE_SYSTEM_NAME": "DOS",
"CMAKE_C_COMPILER_WORKS": "1",
"CMAKE_CXX_COMPILER_WORKS": "1"
}
},
{
"name": "dos32-base",
"hidden": true,
"inherits": "dos-base",
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "x86",
"CMAKE_C_COMPILER": "$env{WATCOM_BINDIR}/wcl386",
"CMAKE_CXX_COMPILER": "$env{WATCOM_BINDIR}/wcl386"
}
},
{
"name": "dos16-base",
"hidden": true,
"inherits": "dos-base",
"cacheVariables": {
"CMAKE_SYSTEM_PROCESSOR": "I86",
"CMAKE_C_COMPILER": "$env{WATCOM_BINDIR}/wcl",
"CMAKE_CXX_COMPILER": "$env{WATCOM_BINDIR}/wcl"
}
},
{
"name": "dos32-debug",
"displayName": "DOS 32-bit (Debug)",
"inherits": "dos32-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "dos32-release",
"displayName": "DOS 32-bit (Release)",
"inherits": "dos32-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "dos16-debug",
"displayName": "DOS 16-bit (Debug)",
"inherits": "dos16-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "dos16-release",
"displayName": "DOS 16-bit (Release)",
"inherits": "dos16-base",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Release"
}
}
],
"buildPresets": [
{
"name": "dos32-debug",
"displayName": "Build DOS 32-bit (Debug)",
"configurePreset": "dos32-debug"
},
{
"name": "dos32-release",
"displayName": "Build DOS 32-bit (Release)",
"configurePreset": "dos32-release"
},
{
"name": "dos16-debug",
"displayName": "Build DOS 16-bit (Debug)",
"configurePreset": "dos16-debug"
},
{
"name": "dos16-release",
"displayName": "Build DOS 16-bit (Release)",
"configurePreset": "dos16-release"
}
]
}Key points:
- Adjust the
WATCOMenvironment values indos-host-linuxanddos-host-windowsto match your actual install paths. -
"condition"blocks ensure only the matching host preset activates — a Linux developer and a Windows developer share the same file. -
CMAKE_C_COMPILER_WORKS/CMAKE_CXX_COMPILER_WORKSare set ascacheVariablesin the preset (not as-Dflags in workspace settings). -
WATCOM_BINDIRis derived fromWATCOM, so compiler paths adapt automatically. -
dos-baseinherits from both host presets; the inactive one is skipped by its condition.
With presets, the workspace settings are minimal:
{
"cmake.useCMakePresets": "always",
"C_Cpp.intelliSenseEngine": "default"
}That's it. No cmake.configureArgs, no cmake.generator override — the presets handle everything.
The MSVC IntelliSense engine cannot interrogate the Watcom compiler, so it needs help. This configuration combines two sources of information:
-
CMake Tools (
configurationProvider) supplies compiler flags and auto-discovered macros from the CMake File API. -
Manual
definesprovide shims for Watcom-specific keywords that IntelliSense cannot parse.
With "mergeConfigurations": true, both sources are merged together.
Why not define __WATCOMC__ manually?
The CMakeLists.txt auto-discovers it (see below), and CMake Tools feeds it to IntelliSense via the configurationProvider. No need to hard-code it.
cmake_minimum_required(VERSION 3.21)
project(MyProject LANGUAGES C CXX VERSION 0.1.0)
set(CMAKE_C_STANDARD 99)
set(CMAKE_CXX_STANDARD 98)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)if(CMAKE_C_COMPILER_ID STREQUAL "OpenWatcom")
add_compile_options(
-zq # Operate quietly (display only error messages)
-wx # Maximum warning level
-fr=nul # Set error file to NUL (discard error file output)
)
if(CMAKE_SYSTEM_PROCESSOR STREQUAL "I86")
# 16-bit DOS
add_compile_options(
-bt=dos # Build target is DOS
-ms # Small memory model (small code/small data)
-0 # 8086 instructions
)
else()
# 32-bit DOS (dos4gw extender)
add_compile_options(
-bt=dos4g # Build target is DOS/4GW protected mode
-5s # Pentium stack calling conventions
-s # Remove stack overflow checks
)
endif()
string(JOIN " " CMAKE_C_FLAGS
${CMAKE_C_FLAGS}
-za99 # Disable extensions, use C99 standard
)
string(JOIN " " CMAKE_CXX_FLAGS
${CMAKE_CXX_FLAGS}
-ze # Enable extensions (near, far, export, etc.)
)
endif()add_executable(${PROJECT_NAME}
${CMAKE_SOURCE_DIR}/src/main.c
)
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_SOURCE_DIR}/include
)
# 8.3-safe output name for DOS compatibility
set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "myproj")Open Watcom defines macros internally (e.g. __WATCOMC__, _M_IX86, __DOS__, __386__) but does not expose them to CMake. This means the CMake File API — and by extension, the CMake Tools configurationProvider in VS Code — cannot discover them. IntelliSense will show false errors for any code that depends on these macros.
The fix: query the compiler with -pm (print macros) using the same target flags, parse the output, and re-inject them as compile definitions. This is a harmless no-op for the real compiler (same-value redefinition) and makes the macros visible to IntelliSense.
if(CMAKE_C_COMPILER_ID STREQUAL "OpenWatcom")
# Collect all compile options so the -pm dump reflects the actual build
# configuration. Resolve generator expressions for the active build type
# since execute_process runs at configure time.
get_directory_property(_WC_ALL_OPTIONS COMPILE_OPTIONS)
set(_WC_PM_FLAGS -pm)
foreach(_opt IN LISTS _WC_ALL_OPTIONS)
if(_opt MATCHES "^\\$<\\$<CONFIG:${CMAKE_BUILD_TYPE}>:(.+)>$")
list(APPEND _WC_PM_FLAGS "${CMAKE_MATCH_1}")
elseif(NOT _opt MATCHES "^\\$<")
list(APPEND _WC_PM_FLAGS "${_opt}")
endif()
endforeach()
execute_process(
COMMAND ${CMAKE_C_COMPILER} ${_WC_PM_FLAGS} /dev/null
OUTPUT_VARIABLE _WC_PM_OUTPUT
RESULT_VARIABLE _WC_PM_RESULT
ERROR_VARIABLE _WC_PM_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE
)
message(VERBOSE "[Watcom -pm] Command: ${CMAKE_C_COMPILER} ${_WC_PM_FLAGS} /dev/null")
message(VERBOSE "[Watcom -pm] Exit code: ${_WC_PM_RESULT}")
if(_WC_PM_ERROR)
message(VERBOSE "[Watcom -pm] Stderr: ${_WC_PM_ERROR}")
endif()
message(VERBOSE "[Watcom -pm] Output:\n${_WC_PM_OUTPUT}")
# Parse "#define NAME VALUE" lines into NAME=VALUE compile definitions
string(REGEX MATCHALL "#define [^\n]+" _WC_MACRO_LINES "${_WC_PM_OUTPUT}")
set(_WC_DEFINES "")
foreach(_line IN LISTS _WC_MACRO_LINES)
if(_line MATCHES "^#define ([^ ]+) (.+)$")
list(APPEND _WC_DEFINES "${CMAKE_MATCH_1}=${CMAKE_MATCH_2}")
elseif(_line MATCHES "^#define ([^ ]+)$")
list(APPEND _WC_DEFINES "${CMAKE_MATCH_1}")
endif()
endforeach()
target_compile_definitions(${PROJECT_NAME} PRIVATE ${_WC_DEFINES})
endif()Note (Windows): Replace
/dev/nullwithNULif you are not using a cross-platform wrapper. A portable alternative is to create an empty file and pass its path instead.
# Configure (pick a preset; --fresh for clean reconfigure)
cmake --preset dos32-debug --fresh
# Build
cmake --build --preset dos32-debug- Open the project folder in VS Code.
- If prompted "Do you trust the authors of the files in this folder?", click Yes, I trust the authors.
- CMake Tools will detect
CMakePresets.jsonand prompt to select a configure preset. Choose one (e.g. DOS 32-bit (Debug)). - Use
Ctrl+Shift+P→ CMake: Build (or pressF7) to build.
Switching between 16-bit and 32-bit targets is as simple as selecting a different preset — IntelliSense updates automatically because mergeConfigurations picks up the new macros from the CMake File API.
| Command | Purpose |
|---|---|
CMake: Select Configure Preset |
Switch between dos32-debug, dos16-release, etc. |
CMake: Build |
Build the current preset (also F7) |
CMake: Delete Cache and Reconfigure |
Clean reconfigure if things get stuck |
CMake: Reset CMake Tools Extension State |
Nuclear option — resets all CMake Tools state |
C/C++: Edit Configurations (JSON) |
Edit c_cpp_properties.json
|
Preferences: Open Workspace Settings (JSON) |
Edit .vscode/settings.json
|
If you previously followed the old instructions using user-local CMake Kits:
- Remove the Open Watcom entries from your user-local
cmake-tools-kits.json(Ctrl+Shift+P→CMake: Edit User-Local CMake Kits). - Remove
cmake.configureArgs,cmake.generator, andC_Cpp.default.configurationProviderfrom.vscode/settings.json. - Add the
CMakePresets.json, updatedsettings.json, and updatedc_cpp_properties.jsonfiles shown above. - Restart VS Code.
- Welcome
- Building
- Open Watcom Documentation
- Notes
- Relicensing effort
- Debugging
- OW tools usage Overview
- OW tools usage with CMake
- OW tools usage with Visual Studio Code
- Open Watcom 1.9 Wiki
OW Development
WGML Development
- WGML
- Augmented Devices
- Binary Device Files
- Common File Blocks
- COP Files
- Device File Blocks
- Device Function Language
- Device Function Notes
- Device Functions
- Directory File Format
- Drawing Boxes
- Driver File Blocks
- File and Directory Names
- Font File Blocks
- Fonts
- GML Tag Notes
- Keyword Statistics
- Macros and User Defined Tags
- Meta Data
- Page Layout Subsystem
- Search Paths
- Sequencing
- System Symbol Notes
- Tabs and Tabbing
- whpcvt Utility interaction
{ // Set WATCOM to your Open Watcom install path. // Example: "C:/WATCOM" on Windows, "/opt/watcom" on Linux. "env": { "WATCOM": "/opt/watcom" }, "configurations": [ { "name": "Watcom DOS", "includePath": [ "${workspaceFolder}/include/**", "${WATCOM}/h/**" ], // CMake Tools supplies compiler flags and Watcom built-in macros // (auto-discovered via -pm in CMakeLists.txt) based on the active // preset. Switching presets automatically updates IntelliSense. "configurationProvider": "ms-vscode.cmake-tools", // Merge our manual shims on top of what CMake Tools reports, // so both the auto-discovered macros and the shims take effect. "mergeConfigurations": true, // IntelliSense-only shims for Watcom constructs that the MSVC // IntelliSense engine cannot parse. These must NOT be passed to // the real compiler. "defines": [ // Watcom pragma keywords — remap to MSVC push/pop so // #pragma pack(__push, N) parses correctly "__push=push", "__pop=pop", // Calling-convention macros that resolve to // __declspec(__watcall) in _comdef.h. Emptying them avoids // IntelliSense errors. Safe because _comdef.h guards each // with #ifndef. "_WCRTLINK=", "_WCIRTLINK=", "_WCRTDATA=", "_WPRTLINK=", "_WMRTLINK=", // Watcom compiler keywords used throughout the headers // (_comdef.h maps _WCNEAR->__near, _WCFAR->__far, etc.). // IntelliSense doesn't understand these, so they are // defined to nothing. "__near=", "__far=", "__huge=", "__interrupt=", "__fortran=", "__watcall=", "__loadds=", "__saveregs=", "__export=", "__far16=" ], "cStandard": "c99", "cppStandard": "c++98", "intelliSenseMode": "msvc-x86", // Empty string disables built-in compiler querying. IntelliSense // cannot interrogate the Watcom compiler, so we rely entirely on // the configurationProvider + manual shims above. "compilerPath": "" } ], "version": 4 }