Repository: conan-io/conan
Pull request #18520 (2025-06-24 16:35:00)

Added threads subsetting in emcc compiler model
Changelog: Feature: Added `threads` subsetting in `emcc` compiler model
Docs: https://github.com/conan-io/docs/pull/4115

Close https://github.com/conan-io/conan/issues/10088

The `emcc` compiler generates binaries that may be incompatible depending on whether threads are used. For more details, refer to the "Note" section in the Emscripten documentation: https://emscripten.org/docs/porting/pthreads.html#compiling-with-pthreads-enabled.

According to https://emscripten.org/docs/api_reference/wasm_workers.html:

> Emscripten supports two multithreading APIs to utilize this web feature:
> * POSIX Threads (Pthreads) API
> * Wasm Workers API

These two APIs are incompatible with each other.

This incompatibility necessitates the modeling of threading usage within the compiler's binary model. This allows us to distinguish between binaries compiled with threading and those compiled without it. Our goal is to integrate this capability built in, as we strive to provide first-class support for the Emscripten ecosystem.


---

- [x] Refer to the issue that supports this Pull Request.
- [x] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [x] I've read the [Contributing guide](https://github.com/conan-io/conan/blob/develop2/.github/CONTRIBUTING.md).
- [x] I've followed the PEP8 style guides for Python code.
- [x] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one.



Patch:
diff --git a/conan/internal/default_settings.py b/conan/internal/default_settings.py
index 68c19ba0b..0cdbfc358 100644
--- a/conan/internal/default_settings.py
+++ b/conan/internal/default_settings.py
@@ -168,6 +168,7 @@ compiler:
         # There is no ABI compatibility guarantee between versions
         version: [ANY]
         libcxx: [null, libstdc++, libstdc++11, libc++]
+        threads: [null, posix, wasm_workers]
         cppstd: [null, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20, 23, gnu23, 26, gnu26]
         cstd: [null, 99, gnu99, 11, gnu11, 17, gnu17, 23, gnu23]
 
diff --git a/conan/tools/build/flags.py b/conan/tools/build/flags.py
index 49156c5ed..2b3991fa8 100644
--- a/conan/tools/build/flags.py
+++ b/conan/tools/build/flags.py
@@ -195,6 +195,18 @@ def build_type_flags(conanfile):
             return flags
     return []
 
+def threads_flags(conanfile):
+    """
+    returns flags specific to the threading model used by the compiler
+    """
+    compiler = conanfile.settings.get_safe("compiler")
+    threads = conanfile.settings.get_safe("compiler.threads")
+    if compiler == "emcc":
+        if threads == "posix":
+            return ["-pthread"]
+        elif threads == "wasm_workers":
+            return ["-sWASM_WORKERS=1"]
+    return []
 
 def llvm_clang_front(conanfile):
     # Only Windows clang with MSVC backend (LLVM/Clang, not MSYS2 clang)
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index d2a77fda6..7dec828d3 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -10,7 +10,7 @@ from conan.tools.apple.apple import get_apple_sdk_fullname, _to_apple_arch
 from conan.tools.android.utils import android_abi
 from conan.tools.apple.apple import is_apple_os, to_apple_arch
 from conan.tools.build import build_jobs
-from conan.tools.build.flags import architecture_flag, architecture_link_flag, libcxx_flags
+from conan.tools.build.flags import architecture_flag, architecture_link_flag, libcxx_flags, threads_flags
 from conan.tools.build.cross_building import cross_building
 from conan.tools.cmake.toolchain import CONAN_TOOLCHAIN_FILENAME
 from conan.tools.cmake.utils import is_multi_configuration
@@ -237,8 +237,8 @@ class SkipRPath(Block):
 
 class ArchitectureBlock(Block):
     template = textwrap.dedent("""\
-        # Define C++ flags, C flags and linker flags from 'settings.arch'
         {% if arch_flag %}
+        # Define C++ flags, C flags and linker flags from 'settings.arch'
         message(STATUS "Conan toolchain: Defining architecture flag: {{ arch_flag }}")
         string(APPEND CONAN_CXX_FLAGS " {{ arch_flag }}")
         string(APPEND CONAN_C_FLAGS " {{ arch_flag }}")
@@ -250,15 +250,23 @@ class ArchitectureBlock(Block):
         string(APPEND CONAN_SHARED_LINKER_FLAGS " {{ arch_link_flag }}")
         string(APPEND CONAN_EXE_LINKER_FLAGS " {{ arch_link_flag }}")
         {% endif %}
+        {% if thread_flags_list %}
+        # Define C++ flags, C flags and linker flags from 'compiler.threads'
+        message(STATUS "Conan toolchain: Defining thread flags: {{ thread_flags_list }}")
+        string(APPEND CONAN_CXX_FLAGS " {{ thread_flags_list }}")
+        string(APPEND CONAN_C_FLAGS " {{ thread_flags_list }}")
+        string(APPEND CONAN_SHARED_LINKER_FLAGS " {{ thread_flags_list }}")
+        string(APPEND CONAN_EXE_LINKER_FLAGS " {{ thread_flags_list }}")
+        {% endif %}
         """)
 
     def context(self):
         arch_flag = architecture_flag(self._conanfile)
         arch_link_flag = architecture_link_flag(self._conanfile)
-        if not arch_flag and not arch_link_flag:
+        thread_flags_list = " ".join(threads_flags(self._conanfile))
+        if not arch_flag and not arch_link_flag and not thread_flags_list:
             return
-        return {"arch_flag": arch_flag, "arch_link_flag": arch_link_flag}
-
+        return {"arch_flag": arch_flag, "arch_link_flag": arch_link_flag, "thread_flags_list": thread_flags_list}
 
 class LinkerScriptsBlock(Block):
     template = textwrap.dedent("""\
diff --git a/conan/tools/gnu/autotoolstoolchain.py b/conan/tools/gnu/autotoolstoolchain.py
index 1b2ecd3c9..e4c008553 100644
--- a/conan/tools/gnu/autotoolstoolchain.py
+++ b/conan/tools/gnu/autotoolstoolchain.py
@@ -7,7 +7,7 @@ from conan.tools.apple.apple import is_apple_os, resolve_apple_flags, apple_extr
 from conan.tools.build import cmd_args_to_string, save_toolchain_args
 from conan.tools.build.cross_building import cross_building
 from conan.tools.build.flags import architecture_flag, architecture_link_flag, build_type_flags, cppstd_flag, \
-    build_type_link_flags, libcxx_flags, cstd_flag, llvm_clang_front
+    build_type_link_flags, libcxx_flags, cstd_flag, llvm_clang_front, threads_flags
 from conan.tools.env import Environment, VirtualBuildEnv
 from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
 from conan.tools.microsoft import VCVars, msvc_runtime_flag, unix_path, check_min_vs, is_msvc
@@ -53,6 +53,7 @@ class AutotoolsToolchain:
         self.cstd = cstd_flag(self._conanfile)
         self.arch_flag = architecture_flag(self._conanfile)
         self.arch_ld_flag = architecture_link_flag(self._conanfile)
+        self.threads_flags = threads_flags(self._conanfile)
         self.libcxx, self.gcc_cxx11_abi = libcxx_flags(self._conanfile)
         self.fpic = self._conanfile.options.get_safe("fPIC")
         self.msvc_runtime_flag = self._get_msvc_runtime_flag()
@@ -203,7 +204,7 @@ class AutotoolsToolchain:
     def cxxflags(self):
         fpic = "-fPIC" if self.fpic else None
         ret = [self.libcxx, self.cppstd, self.arch_flag, fpic, self.msvc_runtime_flag,
-               self.sysroot_flag]
+               self.sysroot_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:cxxflags", default=[], check_type=list)
@@ -214,7 +215,7 @@ class AutotoolsToolchain:
     @property
     def cflags(self):
         fpic = "-fPIC" if self.fpic else None
-        ret = [self.cstd, self.arch_flag, fpic, self.msvc_runtime_flag, self.sysroot_flag]
+        ret = [self.cstd, self.arch_flag, fpic, self.msvc_runtime_flag, self.sysroot_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:cflags", default=[], check_type=list)
@@ -224,7 +225,7 @@ class AutotoolsToolchain:
 
     @property
     def ldflags(self):
-        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag]
+        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[],
diff --git a/conan/tools/gnu/gnutoolchain.py b/conan/tools/gnu/gnutoolchain.py
index 3a478d962..421be382a 100644
--- a/conan/tools/gnu/gnutoolchain.py
+++ b/conan/tools/gnu/gnutoolchain.py
@@ -7,7 +7,7 @@ from conan.tools.build import cmd_args_to_string, save_toolchain_args
 from conan.tools.build.cross_building import cross_building
 from conan.tools.build.flags import architecture_flag, architecture_link_flag, build_type_flags, cppstd_flag, \
     build_type_link_flags, \
-    libcxx_flags, llvm_clang_front
+    libcxx_flags, llvm_clang_front, threads_flags
 from conan.tools.env import Environment, VirtualBuildEnv
 from conan.tools.gnu.get_gnu_triplet import _get_gnu_triplet
 from conan.tools.microsoft import VCVars, msvc_runtime_flag, unix_path, check_min_vs, is_msvc
@@ -58,6 +58,7 @@ class GnuToolchain:
         self.cppstd = cppstd_flag(self._conanfile)
         self.arch_flag = architecture_flag(self._conanfile)
         self.arch_ld_flag = architecture_link_flag(self._conanfile)
+        self.threads_flags = threads_flags(self._conanfile)
         self.libcxx, self.gcc_cxx11_abi = libcxx_flags(self._conanfile)
         self.fpic = self._conanfile.options.get_safe("fPIC")
         self.msvc_runtime_flag = self._get_msvc_runtime_flag()
@@ -268,7 +269,7 @@ class GnuToolchain:
     def cxxflags(self):
         fpic = "-fPIC" if self.fpic else None
         ret = [self.libcxx, self.cppstd, self.arch_flag, fpic, self.msvc_runtime_flag,
-               self.sysroot_flag]
+               self.sysroot_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:cxxflags", default=[], check_type=list)
@@ -279,7 +280,7 @@ class GnuToolchain:
     @property
     def cflags(self):
         fpic = "-fPIC" if self.fpic else None
-        ret = [self.arch_flag, fpic, self.msvc_runtime_flag, self.sysroot_flag]
+        ret = [self.arch_flag, fpic, self.msvc_runtime_flag, self.sysroot_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:cflags", default=[], check_type=list)
@@ -289,7 +290,7 @@ class GnuToolchain:
 
     @property
     def ldflags(self):
-        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag]
+        ret = [self.arch_flag, self.sysroot_flag, self.arch_ld_flag] + self.threads_flags
         apple_flags = [self.apple_isysroot_flag, self.apple_arch_flag, self.apple_min_version_flag]
         apple_flags += self.apple_extra_flags
         conf_flags = self._conanfile.conf.get("tools.build:sharedlinkflags", default=[],
diff --git a/conan/tools/meson/toolchain.py b/conan/tools/meson/toolchain.py
index c1f1e79ed..ece0fdb2e 100644
--- a/conan/tools/meson/toolchain.py
+++ b/conan/tools/meson/toolchain.py
@@ -9,7 +9,7 @@ from conan.internal.internal_tools import raise_on_universal_arch
 from conan.tools.apple.apple import is_apple_os, apple_min_version_flag, \
     resolve_apple_flags, apple_extra_flags
 from conan.tools.build.cross_building import cross_building
-from conan.tools.build.flags import architecture_link_flag, libcxx_flags, architecture_flag
+from conan.tools.build.flags import architecture_link_flag, libcxx_flags, architecture_flag, threads_flags
 from conan.tools.env import VirtualBuildEnv
 from conan.tools.meson.helpers import *
 from conan.tools.meson.helpers import get_apple_subsystem
@@ -218,6 +218,8 @@ class MesonToolchain:
         self.arch_flag = architecture_flag(self._conanfile)  # https://github.com/conan-io/conan/issues/17624
         #: Architecture link flag deduced by Conan and added to ``c_link_args`` and ``cpp_link_args``
         self.arch_link_flag = architecture_link_flag(self._conanfile)
+        #: Threads flags deduced by Conan and added to ``c_args``, ``cpp_args``, ``c_link_args`` and ``cpp_link_args``
+        self.threads_flags = threads_flags(self._conanfile)
         #: Dict-like object that defines Meson ``properties`` with ``key=value`` format
         self.properties = {}
         #: Dict-like object that defines Meson ``project options`` with ``key=value`` format
@@ -453,14 +455,14 @@ class MesonToolchain:
         linker_script_flags = ['-T"' + linker_script + '"' for linker_script in linker_scripts]
         defines = self._conanfile_conf.get("tools.build:defines", default=[], check_type=list)
         sys_root = [f"--sysroot={self._sys_root}"] if self._sys_root else [""]
-        ld = sharedlinkflags + exelinkflags + linker_script_flags + sys_root + self.extra_ldflags
+        ld = sharedlinkflags + exelinkflags + linker_script_flags + sys_root + self.extra_ldflags + self.threads_flags
         # Apple extra flags from confs (visibilty, bitcode, arc)
         cxxflags += self.apple_extra_flags
         cflags += self.apple_extra_flags
         ld += self.apple_extra_flags
         return {
-            "cxxflags": [self.arch_flag] + cxxflags + sys_root + self.extra_cxxflags,
-            "cflags": [self.arch_flag] + cflags + sys_root + self.extra_cflags,
+            "cxxflags": [self.arch_flag] + cxxflags + sys_root + self.extra_cxxflags + self.threads_flags,
+            "cflags": [self.arch_flag] + cflags + sys_root + self.extra_cflags + self.threads_flags,
             "ldflags": [self.arch_flag] + [self.arch_link_flag] + ld,
             "defines": [f"-D{d}" for d in (defines + self.extra_defines)]
         }
diff --git a/conan/tools/premake/toolchain.py b/conan/tools/premake/toolchain.py
index 346165240..0131cf6da 100644
--- a/conan/tools/premake/toolchain.py
+++ b/conan/tools/premake/toolchain.py
@@ -1,4 +1,4 @@
-from conan.tools.build.flags import architecture_flag, architecture_link_flag, libcxx_flags
+from conan.tools.build.flags import architecture_flag, architecture_link_flag, libcxx_flags, threads_flags
 import os
 import textwrap
 from pathlib import Path
@@ -16,19 +16,19 @@ def _generate_flags(self, conanfile):
     template = textwrap.dedent(
         """\
         {% if extra_cflags %}
-        -- C flags retrieved from CFLAGS environment, conan.conf(tools.build:cflags) and extra_cflags
+        -- C flags retrieved from CFLAGS environment, conan.conf(tools.build:cflags), extra_cflags and compiler settings
         filter { files { "**.c" } }
             buildoptions { {{ extra_cflags }} }
         filter {}
         {% endif %}
         {% if extra_cxxflags %}
-        -- CXX flags retrieved from CXXFLAGS environment, conan.conf(tools.build:cxxflags) and extra_cxxflags
+        -- CXX flags retrieved from CXXFLAGS environment, conan.conf(tools.build:cxxflags), extra_cxxflags and compiler settings
         filter { files { "**.cpp", "**.cxx", "**.cc" } }
             buildoptions { {{ extra_cxxflags }} }
         filter {}
         {% endif %}
         {% if extra_ldflags %}
-        -- Link flags retrieved from LDFLAGS environment, conan.conf(tools.build:sharedlinkflags), conan.conf(tools.build:exelinkflags) and extra_cxxflags
+        -- Link flags retrieved from LDFLAGS environment, conan.conf(tools.build:sharedlinkflags), conan.conf(tools.build:exelinkflags), extra_cxxflags and compiler settings
         linkoptions { {{ extra_ldflags }} }
         {% endif %}
         {% if extra_defines %}
@@ -47,6 +47,7 @@ def _generate_flags(self, conanfile):
     arch_flags = to_list(architecture_flag(self._conanfile))
     cxx_flags, libcxx_compile_definitions = libcxx_flags(self._conanfile)
     arch_link_flags = to_list(architecture_link_flag(self._conanfile))
+    thread_flags_list = threads_flags(self._conanfile)
 
     extra_defines = format_list(
         conanfile.conf.get("tools.build:defines", default=[], check_type=list)
@@ -54,13 +55,17 @@ def _generate_flags(self, conanfile):
         + to_list(libcxx_compile_definitions)
     )
     extra_c_flags = format_list(
-        conanfile.conf.get("tools.build:cflags", default=[], check_type=list) + self.extra_cflags + arch_flags
+        conanfile.conf.get("tools.build:cflags", default=[], check_type=list)
+        + self.extra_cflags
+        + arch_flags
+        + thread_flags_list
     )
     extra_cxx_flags = format_list(
         conanfile.conf.get("tools.build:cxxflags", default=[], check_type=list)
         + to_list(cxx_flags)
         + self.extra_cxxflags
         + arch_flags
+        + thread_flags_list
     )
     extra_ld_flags = format_list(
         conanfile.conf.get("tools.build:sharedlinkflags", default=[], check_type=list)
@@ -68,6 +73,7 @@ def _generate_flags(self, conanfile):
         + self.extra_ldflags
         + arch_flags
         + arch_link_flags
+        + thread_flags_list
     )
 
     return (


Test patch:
diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py
index bbd6931d5..d517e2572 100644
--- a/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -1772,3 +1772,35 @@ def test_cmake_presets_compiler():
     # https://github.com/microsoft/vscode-cmake-tools/blob/a1ceda25ea93fc0060324de15970a8baa69addf6/src/presets/preset.ts#L1095C23-L1095C35
     assert cache_variables["CMAKE_C_COMPILER"] == "cl"
     assert cache_variables["CMAKE_CXX_COMPILER"] == "cl.exe"
+
+@pytest.mark.parametrize(
+    "threads, flags",
+    [("posix", "-pthread"), ("wasm_workers", "-sWASM_WORKERS=1")],
+)
+def test_thread_flags(threads, flags):
+    client = TestClient()
+    profile = textwrap.dedent(f"""
+        [settings]
+        arch=wasm
+        build_type=Release
+        compiler=emcc
+        compiler.cppstd=17
+        compiler.threads={threads}
+        compiler.libcxx=libc++
+        compiler.version=4.0.10
+        os=Emscripten
+        """)
+    client.save(
+        {
+            "conanfile.py": GenConanfile("pkg", "1.0")
+            .with_settings("os", "arch", "compiler", "build_type")
+            .with_generator("CMakeToolchain"),
+            "profile": profile,
+        }
+    )
+    client.run("install . -pr=./profile")
+    toolchain = client.load("conan_toolchain.cmake")
+    assert f'string(APPEND CONAN_CXX_FLAGS " {flags}")' in toolchain
+    assert f'string(APPEND CONAN_C_FLAGS " {flags}")' in toolchain
+    assert f'string(APPEND CONAN_SHARED_LINKER_FLAGS " {flags}")' in toolchain
+    assert f'string(APPEND CONAN_EXE_LINKER_FLAGS " {flags}")' in toolchain
diff --git a/test/integration/toolchains/gnu/test_autotoolstoolchain.py b/test/integration/toolchains/gnu/test_autotoolstoolchain.py
index 95ea899de..7da8302b1 100644
--- a/test/integration/toolchains/gnu/test_autotoolstoolchain.py
+++ b/test/integration/toolchains/gnu/test_autotoolstoolchain.py
@@ -1,6 +1,7 @@
 import os
 import platform
 import textwrap
+import pytest
 
 from conan.test.assets.genconanfile import GenConanfile
 from conan.test.utils.tools import TestClient
@@ -367,3 +368,40 @@ def test_conf_build_does_not_exist():
     tc = c.load("conanautotoolstoolchain.sh")
     assert 'export CC_FOR_BUILD="x86_64-linux-gnu-gcc"' in tc
     assert 'export CXX_FOR_BUILD="x86_64-linux-gnu-g++"' in tc
+
+@pytest.mark.parametrize(
+    "threads, flags",
+    [("posix", "-pthread"), ("wasm_workers", "-sWASM_WORKERS=1")],
+)
+def test_thread_flags(threads, flags):
+    os = platform.system()
+    client = TestClient()
+    profile = textwrap.dedent(f"""
+        [settings]
+        arch=wasm
+        build_type=Release
+        compiler=emcc
+        compiler.cppstd=17
+        compiler.threads={threads}
+        compiler.libcxx=libc++
+        compiler.version=4.0.10
+        os=Emscripten
+        """)
+    client.save(
+        {
+            "conanfile.py": GenConanfile("pkg", "1.0")
+            .with_settings("os", "arch", "compiler", "build_type")
+            .with_generator("AutotoolsToolchain"),
+            "profile": profile,
+        }
+    )
+    client.run("install . -pr=./profile")
+    toolchain = client.load("conanautotoolstoolchain{}".format('.bat' if os == "Windows" else '.sh'))
+    if os == "Windows":
+        assert f'set "CXXFLAGS=%CXXFLAGS% -stdlib=libc++ {flags}"' in toolchain
+        assert f'set "CFLAGS=%CFLAGS% {flags}"' in toolchain
+        assert f'set "LDFLAGS=%LDFLAGS% {flags}' in toolchain
+    else:
+        assert f'export CXXFLAGS="$CXXFLAGS -stdlib=libc++ {flags}"' in toolchain
+        assert f'export CFLAGS="$CFLAGS {flags}"' in toolchain
+        assert f'export LDFLAGS="$LDFLAGS {flags}"' in toolchain
diff --git a/test/integration/toolchains/gnu/test_gnutoolchain.py b/test/integration/toolchains/gnu/test_gnutoolchain.py
index 6493a3be2..5294123ed 100644
--- a/test/integration/toolchains/gnu/test_gnutoolchain.py
+++ b/test/integration/toolchains/gnu/test_gnutoolchain.py
@@ -592,3 +592,43 @@ def test_toolchain_crossbuild_to_android():
         "conanfile.py": consumer
     })
     client.run("create . -pr:h host -pr:b build")
+
+
+@pytest.mark.parametrize(
+    "threads, flags",
+    [("posix", "-pthread"), ("wasm_workers", "-sWASM_WORKERS=1")],
+)
+def test_thread_flags(threads, flags):
+    client = TestClient()
+    profile = textwrap.dedent(f"""
+        [settings]
+        arch=wasm
+        build_type=Release
+        compiler=emcc
+        compiler.cppstd=17
+        compiler.threads={threads}
+        compiler.libcxx=libc++
+        compiler.version=4.0.10
+        os=Emscripten
+        """)
+    client.save(
+        {
+            "conanfile.py": GenConanfile("pkg", "1.0")
+            .with_settings("os", "arch", "compiler", "build_type")
+            .with_generator("GnuToolchain"),
+            "profile": profile,
+        }
+    )
+    client.run("install . -pr=./profile")
+    os = platform.system()
+    toolchain = client.load(
+        "conangnutoolchain{}".format('.bat' if os == "Windows" else '.sh'))
+
+    if os == "Windows":
+        assert f'set "CXXFLAGS=%CXXFLAGS% -stdlib=libc++ {flags}"' in toolchain
+        assert f'set "CFLAGS=%CFLAGS% {flags}"' in toolchain
+        assert f'set "LDFLAGS=%LDFLAGS% {flags}' in toolchain
+    else:
+        assert f'export CXXFLAGS="$CXXFLAGS -stdlib=libc++ {flags}"' in toolchain
+        assert f'export CFLAGS="$CFLAGS {flags}"' in toolchain
+        assert f'export LDFLAGS="$LDFLAGS {flags}"' in toolchain
diff --git a/test/integration/toolchains/meson/test_mesontoolchain.py b/test/integration/toolchains/meson/test_mesontoolchain.py
index 699da0a5f..f6e51c6af 100644
--- a/test/integration/toolchains/meson/test_mesontoolchain.py
+++ b/test/integration/toolchains/meson/test_mesontoolchain.py
@@ -823,3 +823,35 @@ def test_conf_extra_apple_flags():
         assert f"{flags} = ['-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden']" in tc
     for flags in ["objcpp_args", "objc_args"]:
         assert f"{flags} = ['-fno-objc-arc', '-m64', '-fvisibility=hidden', '-fvisibility-inlines-hidden']" in tc
+
+@pytest.mark.parametrize(
+    "threads, flags",
+    [("posix", "-pthread"), ("wasm_workers", "-sWASM_WORKERS=1")],
+)
+def test_thread_flags(threads, flags):
+    client = TestClient()
+    profile = textwrap.dedent(f"""
+        [settings]
+        arch=wasm
+        build_type=Release
+        compiler=emcc
+        compiler.cppstd=17
+        compiler.threads={threads}
+        compiler.libcxx=libc++
+        compiler.version=4.0.10
+        os=Emscripten
+        """)
+    client.save(
+        {
+            "conanfile.py": GenConanfile("pkg", "1.0")
+            .with_settings("os", "arch", "compiler", "build_type")
+            .with_generator("MesonToolchain"),
+            "profile": profile,
+        }
+    )
+    client.run("install . -pr=./profile")
+    toolchain = client.load("conan_meson_cross.ini")
+    assert f"c_args = ['{flags}']" in toolchain
+    assert f"c_link_args = ['{flags}']" in toolchain
+    assert f"cpp_args = ['{flags}', '-stdlib=libc++']" in toolchain
+    assert f"cpp_link_args = ['{flags}', '-stdlib=libc++']" in toolchain
diff --git a/test/integration/toolchains/premake/test_premaketoolchain.py b/test/integration/toolchains/premake/test_premaketoolchain.py
index b6bdf0911..b764579a0 100644
--- a/test/integration/toolchains/premake/test_premaketoolchain.py
+++ b/test/integration/toolchains/premake/test_premaketoolchain.py
@@ -1,4 +1,6 @@
 import textwrap
+from conan.test.assets.genconanfile import GenConanfile
+import pytest
 
 from conan.test.utils.tools import TestClient
 from conan.tools.premake.toolchain import PremakeToolchain
@@ -58,7 +60,6 @@ def test_extra_flags_via_conf():
     assert 'defines { "define1=0", "_GLIBCXX_USE_CXX11_ABI=0" }' in content
 
 
-
 def test_project_configuration():
     tc = TestClient(path_with_spaces=False)
     profile = textwrap.dedent(
@@ -132,7 +133,7 @@ def test_project_configuration():
         textwrap.dedent(
             """
     project "main"
-        -- CXX flags retrieved from CXXFLAGS environment, conan.conf(tools.build:cxxflags) and extra_cxxflags
+        -- CXX flags retrieved from CXXFLAGS environment, conan.conf(tools.build:cxxflags), extra_cxxflags and compiler settings
         filter { files { "**.cpp", "**.cxx", "**.cc" } }
             buildoptions { "-stdlib=libc++", "-FS" }
         filter {}
@@ -151,3 +152,51 @@ def test_project_configuration():
         )
         in toolchain
     )
+
+
+@pytest.mark.parametrize(
+    "threads, flags",
+    [("posix", "-pthread"), ("wasm_workers", "-sWASM_WORKERS=1")],
+)
+def test_thread_flags(threads, flags):
+    client = TestClient()
+    profile = textwrap.dedent(f"""
+        [settings]
+        arch=wasm64
+        build_type=Release
+        compiler=emcc
+        compiler.cppstd=17
+        compiler.threads={threads}
+        compiler.libcxx=libc++
+        compiler.version=4.0.10
+        os=Emscripten
+        """)
+    client.save(
+        {
+            "conanfile.py": GenConanfile("pkg", "1.0")
+            .with_settings("os", "arch", "compiler", "build_type")
+            .with_generator("PremakeToolchain"),
+            "profile": profile,
+        }
+    )
+    client.run("install . -pr=./profile")
+    toolchain = client.load("conantoolchain.premake5.lua")
+    assert (
+        """
+        filter { files { "**.c" } }
+            buildoptions { "-sMEMORY64=1", "%s" }
+        filter {}
+        """
+        % flags
+        in toolchain
+    )
+    assert (
+        """
+        filter { files { "**.cpp", "**.cxx", "**.cc" } }
+            buildoptions { "-stdlib=libc++", "-sMEMORY64=1", "%s" }
+        filter {}
+        """
+        % flags
+        in toolchain
+    )
+    assert 'linkoptions { "-sMEMORY64=1", "%s" }' % flags in toolchain
diff --git a/test/unittests/client/build/compiler_flags_test.py b/test/unittests/client/build/compiler_flags_test.py
index 4c82661f5..0cbab683e 100644
--- a/test/unittests/client/build/compiler_flags_test.py
+++ b/test/unittests/client/build/compiler_flags_test.py
@@ -1,7 +1,7 @@
 import unittest
 from parameterized.parameterized import parameterized
 
-from conan.tools.build.flags import architecture_flag, build_type_flags
+from conan.tools.build.flags import architecture_flag, build_type_flags, threads_flags
 from conan.test.utils.mocks import MockSettings, ConanFileMock
 
 
@@ -37,6 +37,19 @@ class CompilerFlagsTest(unittest.TestCase):
         conanfile.settings = settings
         self.assertEqual(architecture_flag(conanfile), flag)
 
+
+    @parameterized.expand([("clang", None, []),
+                           ("emcc", None, []),
+                           ("emcc", "posix", ["-pthread"]),
+                           ("emcc", "wasm_workers", ["-sWASM_WORKERS=1"]),
+                           ])
+    def test_threads_flag(self, compiler, threads, flag):
+        settings = MockSettings({"compiler": compiler,
+                                 "compiler.threads": threads})
+        conanfile = ConanFileMock()
+        conanfile.settings = settings
+        self.assertEqual(threads_flags(conanfile), flag)
+
     @parameterized.expand([("clang", "x86", "Windows", ""),
                            ("clang", "x86_64", "Windows", "")
                            ])