mirror of
https://github.com/Kitware/CMake.git
synced 2026-02-17 04:31:04 -06:00
AIX: Add an option to disable automatic exports from shared libraries
Since commit 0f150b69d3 (AIX: Explicitly compute shared object exports
for both XL and GNU, 2019-07-11, v3.16.0-rc1~418^2~2) we always export
all symbols from shared libraries by default. Add a new target property
called `AIX_EXPORT_ALL_SYMBOLS` that can be explicitly set to OFF to
suppress this behavior and export no symbols by default.
Fixes: #20290
This commit is contained in:
@@ -104,6 +104,7 @@ Properties on Targets
|
|||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
/prop_tgt/ADDITIONAL_CLEAN_FILES
|
/prop_tgt/ADDITIONAL_CLEAN_FILES
|
||||||
|
/prop_tgt/AIX_EXPORT_ALL_SYMBOLS
|
||||||
/prop_tgt/ALIASED_TARGET
|
/prop_tgt/ALIASED_TARGET
|
||||||
/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
|
/prop_tgt/ANDROID_ANT_ADDITIONAL_OPTIONS
|
||||||
/prop_tgt/ANDROID_API
|
/prop_tgt/ANDROID_API
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ Variables that Control the Build
|
|||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
|
||||||
|
/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS
|
||||||
/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
|
/variable/CMAKE_ANDROID_ANT_ADDITIONAL_OPTIONS
|
||||||
/variable/CMAKE_ANDROID_API
|
/variable/CMAKE_ANDROID_API
|
||||||
/variable/CMAKE_ANDROID_API_MIN
|
/variable/CMAKE_ANDROID_API_MIN
|
||||||
|
|||||||
12
Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
Normal file
12
Help/prop_tgt/AIX_EXPORT_ALL_SYMBOLS.rst
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
AIX_EXPORT_ALL_SYMBOLS
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
On AIX, CMake automatically exports all symbols from shared libraries, and
|
||||||
|
from executables with the :prop_tgt:`ENABLE_EXPORTS` target property set.
|
||||||
|
Explicitly disable this boolean property to suppress the behavior and
|
||||||
|
export no symbols by default. In this case it is expected that the project
|
||||||
|
will use other means to export some symbols.
|
||||||
|
|
||||||
|
This property is initialized by the value of
|
||||||
|
the :variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable if it is set
|
||||||
|
when a target is created.
|
||||||
7
Help/release/dev/aix-no-export-all.rst
Normal file
7
Help/release/dev/aix-no-export-all.rst
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
aix-no-export-all
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
* The :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property and associated
|
||||||
|
:variable:`CMAKE_AIX_EXPORT_ALL_SYMBOLS` variable were created to
|
||||||
|
optionally explicitly disbale automatic export of symbols from shared
|
||||||
|
libraries on AIX.
|
||||||
6
Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
Normal file
6
Help/variable/CMAKE_AIX_EXPORT_ALL_SYMBOLS.rst
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
CMAKE_AIX_EXPORT_ALL_SYMBOLS
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
Default value for :prop_tgt:`AIX_EXPORT_ALL_SYMBOLS` target property.
|
||||||
|
This variable is used to initialize the property on each target as it is
|
||||||
|
created.
|
||||||
@@ -23,11 +23,11 @@ macro(__aix_compiler_gnu lang)
|
|||||||
# Construct the export list ourselves to pass only the object files so
|
# Construct the export list ourselves to pass only the object files so
|
||||||
# that we export only the symbols actually provided by the sources.
|
# that we export only the symbols actually provided by the sources.
|
||||||
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
|
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
|
||||||
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <OBJECTS>"
|
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS> <OBJECTS>"
|
||||||
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
|
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
|
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
|
||||||
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <OBJECTS>"
|
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
|
||||||
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
endmacro()
|
endmacro()
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ macro(__aix_compiler_xl lang)
|
|||||||
# Construct the export list ourselves to pass only the object files so
|
# Construct the export list ourselves to pass only the object files so
|
||||||
# that we export only the symbols actually provided by the sources.
|
# that we export only the symbols actually provided by the sources.
|
||||||
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
|
set(CMAKE_${lang}_CREATE_SHARED_LIBRARY
|
||||||
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp${_OBJECTS}"
|
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <OBJECT_DIR>/exports.exp <AIX_EXPORTS>${_OBJECTS}"
|
||||||
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
|
"<CMAKE_${lang}_COMPILER> <CMAKE_SHARED_LIBRARY_${lang}_FLAGS> -Wl,-bE:<OBJECT_DIR>/exports.exp <LANGUAGE_COMPILE_FLAGS> <LINK_FLAGS> <CMAKE_SHARED_LIBRARY_CREATE_${lang}_FLAGS> <SONAME_FLAG><TARGET_SONAME> -o <TARGET> <OBJECTS> <LINK_LIBRARIES>"
|
||||||
)
|
)
|
||||||
|
|
||||||
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
|
set(CMAKE_${lang}_LINK_EXECUTABLE_WITH_EXPORTS
|
||||||
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <OBJECTS>"
|
"\"${CMAKE_ROOT}/Modules/Platform/AIX/ExportImportList\" -o <TARGET_IMPLIB> -l . <AIX_EXPORTS> <OBJECTS>"
|
||||||
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
"<CMAKE_${lang}_COMPILER> <FLAGS> <CMAKE_${lang}_LINK_FLAGS> -Wl,-bE:<TARGET_IMPLIB> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
|
|
||||||
unset(_OBJECTS)
|
unset(_OBJECTS)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "cmSourceFile.h"
|
#include "cmSourceFile.h"
|
||||||
#include "cmStateTypes.h"
|
#include "cmStateTypes.h"
|
||||||
#include "cmStringAlgorithms.h"
|
#include "cmStringAlgorithms.h"
|
||||||
|
#include "cmTarget.h"
|
||||||
|
|
||||||
cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
|
cmCommonTargetGenerator::cmCommonTargetGenerator(cmGeneratorTarget* gt)
|
||||||
: GeneratorTarget(gt)
|
: GeneratorTarget(gt)
|
||||||
@@ -216,6 +217,20 @@ std::string cmCommonTargetGenerator::GetManifests(const std::string& config)
|
|||||||
return cmJoin(manifests, " ");
|
return cmJoin(manifests, " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string cmCommonTargetGenerator::GetAIXExports(std::string const&)
|
||||||
|
{
|
||||||
|
std::string aixExports;
|
||||||
|
if (this->GeneratorTarget->Target->IsAIX()) {
|
||||||
|
if (const char* exportAll =
|
||||||
|
this->GeneratorTarget->GetProperty("AIX_EXPORT_ALL_SYMBOLS")) {
|
||||||
|
if (cmIsOff(exportAll)) {
|
||||||
|
aixExports = "-n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aixExports;
|
||||||
|
}
|
||||||
|
|
||||||
void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
|
void cmCommonTargetGenerator::AppendOSXVerFlag(std::string& flags,
|
||||||
const std::string& lang,
|
const std::string& lang,
|
||||||
const char* name, bool so)
|
const char* name, bool so)
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ protected:
|
|||||||
std::string GetDefines(const std::string& l, const std::string& config);
|
std::string GetDefines(const std::string& l, const std::string& config);
|
||||||
std::string GetIncludes(std::string const& l, const std::string& config);
|
std::string GetIncludes(std::string const& l, const std::string& config);
|
||||||
std::string GetManifests(const std::string& config);
|
std::string GetManifests(const std::string& config);
|
||||||
|
std::string GetAIXExports(std::string const& config);
|
||||||
|
|
||||||
std::vector<std::string> GetLinkedTargetDirectories(
|
std::vector<std::string> GetLinkedTargetDirectories(
|
||||||
const std::string& config) const;
|
const std::string& config) const;
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
|
|||||||
this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
|
this->CreateObjectLists(useLinkScript, false, useResponseFileForObjects,
|
||||||
buildObjs, depends, useWatcomQuote);
|
buildObjs, depends, useWatcomQuote);
|
||||||
|
|
||||||
|
std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
|
||||||
|
|
||||||
cmRulePlaceholderExpander::RuleVariables vars;
|
cmRulePlaceholderExpander::RuleVariables vars;
|
||||||
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
|
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
|
||||||
|
|
||||||
@@ -219,6 +221,7 @@ void cmMakefileExecutableTargetGenerator::WriteDeviceExecutableRule(
|
|||||||
cmOutputConverter::SHELL);
|
cmOutputConverter::SHELL);
|
||||||
|
|
||||||
vars.Language = linkLanguage.c_str();
|
vars.Language = linkLanguage.c_str();
|
||||||
|
vars.AIXExports = aixExports.c_str();
|
||||||
vars.Objects = buildObjs.c_str();
|
vars.Objects = buildObjs.c_str();
|
||||||
vars.ObjectDir = objectDir.c_str();
|
vars.ObjectDir = objectDir.c_str();
|
||||||
vars.Target = target.c_str();
|
vars.Target = target.c_str();
|
||||||
|
|||||||
@@ -727,6 +727,8 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
|
|||||||
cmOutputConverter::SHELL);
|
cmOutputConverter::SHELL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string const& aixExports = this->GetAIXExports(this->GetConfigName());
|
||||||
|
|
||||||
// maybe create .def file from list of objects
|
// maybe create .def file from list of objects
|
||||||
this->GenDefFile(real_link_commands);
|
this->GenDefFile(real_link_commands);
|
||||||
|
|
||||||
@@ -756,6 +758,7 @@ void cmMakefileLibraryTargetGenerator::WriteLibraryRules(
|
|||||||
vars.CMTargetType =
|
vars.CMTargetType =
|
||||||
cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
|
cmState::GetTargetTypeName(this->GeneratorTarget->GetType());
|
||||||
vars.Language = linkLanguage.c_str();
|
vars.Language = linkLanguage.c_str();
|
||||||
|
vars.AIXExports = aixExports.c_str();
|
||||||
vars.Objects = buildObjs.c_str();
|
vars.Objects = buildObjs.c_str();
|
||||||
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
|
std::string objectDir = this->GeneratorTarget->GetSupportDirectory();
|
||||||
|
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkRule(bool useResponseFile,
|
|||||||
|
|
||||||
std::string lang = this->TargetLinkLanguage(config);
|
std::string lang = this->TargetLinkLanguage(config);
|
||||||
vars.Language = config.c_str();
|
vars.Language = config.c_str();
|
||||||
|
vars.AIXExports = "$AIX_EXPORTS";
|
||||||
|
|
||||||
if (this->TargetLinkLanguage(config) == "Swift") {
|
if (this->TargetLinkLanguage(config) == "Swift") {
|
||||||
vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
|
vars.SwiftLibraryName = "$SWIFT_LIBRARY_NAME";
|
||||||
@@ -955,6 +956,7 @@ void cmNinjaNormalTargetGenerator::WriteLinkStatement(
|
|||||||
vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
|
vars["LINK_FLAGS"] = globalGen->EncodeLiteral(vars["LINK_FLAGS"]);
|
||||||
|
|
||||||
vars["MANIFESTS"] = this->GetManifests(config);
|
vars["MANIFESTS"] = this->GetManifests(config);
|
||||||
|
vars["AIX_EXPORTS"] = this->GetAIXExports(config);
|
||||||
|
|
||||||
vars["LINK_PATH"] = frameworkPath + linkPath;
|
vars["LINK_PATH"] = frameworkPath + linkPath;
|
||||||
std::string lwyuFlags;
|
std::string lwyuFlags;
|
||||||
|
|||||||
@@ -85,6 +85,11 @@ std::string cmRulePlaceholderExpander::ExpandRuleVariable(
|
|||||||
return replaceValues.ObjectsQuoted;
|
return replaceValues.ObjectsQuoted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (replaceValues.AIXExports) {
|
||||||
|
if (variable == "AIX_EXPORTS") {
|
||||||
|
return replaceValues.AIXExports;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (replaceValues.Defines && variable == "DEFINES") {
|
if (replaceValues.Defines && variable == "DEFINES") {
|
||||||
return replaceValues.Defines;
|
return replaceValues.Defines;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ public:
|
|||||||
const char* TargetVersionMajor;
|
const char* TargetVersionMajor;
|
||||||
const char* TargetVersionMinor;
|
const char* TargetVersionMinor;
|
||||||
const char* Language;
|
const char* Language;
|
||||||
|
const char* AIXExports;
|
||||||
const char* Objects;
|
const char* Objects;
|
||||||
const char* Target;
|
const char* Target;
|
||||||
const char* LinkLibraries;
|
const char* LinkLibraries;
|
||||||
|
|||||||
@@ -491,6 +491,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type,
|
|||||||
}
|
}
|
||||||
if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
|
if (impl->TargetType == cmStateEnums::SHARED_LIBRARY ||
|
||||||
impl->TargetType == cmStateEnums::EXECUTABLE) {
|
impl->TargetType == cmStateEnums::EXECUTABLE) {
|
||||||
|
initProp("AIX_EXPORT_ALL_SYMBOLS");
|
||||||
initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
|
initProp("WINDOWS_EXPORT_ALL_SYMBOLS");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
[^0]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ERROR: Undefined symbol: .AIXNotExported
|
||||||
7
Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
Normal file
7
Tests/RunCMake/AutoExportDll/AIXExportExplicit.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
enable_language(C)
|
||||||
|
|
||||||
|
set(CMAKE_AIX_EXPORT_ALL_SYMBOLS OFF)
|
||||||
|
add_library(AIXExportExplicitLib SHARED AIXExportExplicitLib.c)
|
||||||
|
add_executable(AIXExportExplicitMain AIXExportExplicitMain.c)
|
||||||
|
target_link_options(AIXExportExplicitLib PRIVATE LINKER:-bE:${CMAKE_CURRENT_SOURCE_DIR}/AIXExportExplicitLib.exp)
|
||||||
|
target_link_libraries(AIXExportExplicitMain PRIVATE AIXExportExplicitLib)
|
||||||
8
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
Normal file
8
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
int AIXNotExported(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int AIXExportedSymbol(void)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
Normal file
1
Tests/RunCMake/AutoExportDll/AIXExportExplicitLib.exp
Normal file
@@ -0,0 +1 @@
|
|||||||
|
AIXExportedSymbol
|
||||||
7
Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
Normal file
7
Tests/RunCMake/AutoExportDll/AIXExportExplicitMain.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
extern int AIXNotExported(void);
|
||||||
|
extern int AIXExportedSymbol(void);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
return AIXNotExported() + AIXExportedSymbol();
|
||||||
|
}
|
||||||
@@ -55,3 +55,14 @@ if(EXPORTS)
|
|||||||
message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
|
message(SEND_ERROR "\"${EXPORTS_DEF}\" has been updated.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
function(run_AIXExportExplicit)
|
||||||
|
set(RunCMake_TEST_BINARY_DIR "${RunCMake_BINARY_DIR}/AIXExpotExplicit-build")
|
||||||
|
run_cmake(AIXExportExplicit)
|
||||||
|
set(RunCMake_TEST_NO_CLEAN 1)
|
||||||
|
set(RunCMake_TEST_OUTPUT_MERGE TRUE)
|
||||||
|
run_cmake_command(AIXExportExplicit-build ${CMAKE_COMMAND} --build . --config Debug)
|
||||||
|
endfunction()
|
||||||
|
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
|
||||||
|
run_AIXExportExplicit()
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -614,7 +614,10 @@ endif()
|
|||||||
add_RunCMake_test_group(CPack "${cpack_tests}")
|
add_RunCMake_test_group(CPack "${cpack_tests}")
|
||||||
# add a test to make sure symbols are exported from a shared library
|
# add a test to make sure symbols are exported from a shared library
|
||||||
# for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
|
# for MSVC compilers CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS property is used
|
||||||
add_RunCMake_test(AutoExportDll -DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID})
|
add_RunCMake_test(AutoExportDll
|
||||||
|
-DCMAKE_SYSTEM_NAME=${CMAKE_SYSTEM_NAME}
|
||||||
|
-DCMAKE_CXX_COMPILER_ID=${CMAKE_CXX_COMPILER_ID}
|
||||||
|
)
|
||||||
|
|
||||||
add_RunCMake_test(AndroidMK)
|
add_RunCMake_test(AndroidMK)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user